LCOV - code coverage report
Current view: top level - libgnucash/engine - gncInvoice.c (source / functions) Coverage Total Hit
Test: gnucash.info Lines: 62.5 % 1045 653
Test Date: 2025-02-07 16:25:45 Functions: 75.7 % 111 84
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : /********************************************************************\
       2                 :             :  * gncInvoice.c -- the Core Business Invoice                        *
       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,2006 Derek Atkins
      25                 :             :  * Copyright (C) 2003 Linas Vepstas <linas@linas.org>
      26                 :             :  * Copyright (c) 2005 Neil Williams <linux@codehelp.co.uk>
      27                 :             :  * Author: Derek Atkins <warlord@MIT.EDU>
      28                 :             :  */
      29                 :             : 
      30                 :             : #include <config.h>
      31                 :             : 
      32                 :             : #include <inttypes.h>
      33                 :             : #include <glib.h>
      34                 :             : #include <glib/gi18n.h>
      35                 :             : #include <qofinstance-p.h>
      36                 :             : 
      37                 :             : #include "Transaction.h"
      38                 :             : #include "Account.h"
      39                 :             : #include "gncBillTermP.h"
      40                 :             : #include "gncEntry.h"
      41                 :             : #include "gncEntryP.h"
      42                 :             : #include "gnc-features.h"
      43                 :             : #include "gncJobP.h"
      44                 :             : #include "gncInvoice.h"
      45                 :             : #include "gncInvoiceP.h"
      46                 :             : #include "gncOwnerP.h"
      47                 :             : #include "engine-helpers.h"
      48                 :             : 
      49                 :             : struct _gncInvoice
      50                 :             : {
      51                 :             :     QofInstance   inst;
      52                 :             : 
      53                 :             :     const char    *id;
      54                 :             :     const char    *notes;
      55                 :             :     gboolean      active;
      56                 :             : 
      57                 :             :     const char    *billing_id;
      58                 :             :     char          *printname;
      59                 :             :     GncBillTerm   *terms;
      60                 :             :     GList         *entries;
      61                 :             :     GList         *prices;
      62                 :             :     GncOwner      owner;
      63                 :             :     GncOwner      billto;
      64                 :             :     GncJob        *job;
      65                 :             :     time64        date_opened;
      66                 :             :     time64        date_posted;
      67                 :             : 
      68                 :             :     gnc_numeric   to_charge_amount;
      69                 :             : 
      70                 :             :     gnc_commodity *currency;
      71                 :             : 
      72                 :             :     Account       *posted_acc;
      73                 :             :     Transaction   *posted_txn;
      74                 :             :     GNCLot        *posted_lot;
      75                 :             : };
      76                 :             : 
      77                 :             : struct _gncInvoiceClass
      78                 :             : {
      79                 :             :     QofInstanceClass parent_class;
      80                 :             : };
      81                 :             : 
      82                 :             : static QofLogModule log_module = GNC_MOD_BUSINESS;
      83                 :             : 
      84                 :             : #define _GNC_MOD_NAME     GNC_ID_INVOICE
      85                 :             : 
      86                 :             : #define GNC_INVOICE_IS_CN "credit-note"
      87                 :             : #define GNC_INVOICE_DOCLINK "assoc_uri" // this is the old name for the document link, kept for compatibility
      88                 :             : 
      89                 :             : #define SET_STR(obj, member, str) { \
      90                 :             :     if (!g_strcmp0 (member, str)) return; \
      91                 :             :     gncInvoiceBeginEdit (obj); \
      92                 :             :     CACHE_REPLACE (member, str); \
      93                 :             :     }
      94                 :             : 
      95                 :             : static void mark_invoice (GncInvoice *invoice);
      96                 :             : static void
      97                 :         638 : mark_invoice (GncInvoice *invoice)
      98                 :             : {
      99                 :         638 :     qof_instance_set_dirty (&invoice->inst);
     100                 :         638 :     qof_event_gen (&invoice->inst, QOF_EVENT_MODIFY, NULL);
     101                 :         638 : }
     102                 :             : 
     103                 :          97 : QofBook * gncInvoiceGetBook (GncInvoice *x)
     104                 :             : {
     105                 :          97 :     return qof_instance_get_book (QOF_INSTANCE(x));
     106                 :             : }
     107                 :             : 
     108                 :             : /* ================================================================== */
     109                 :             : 
     110                 :             : enum
     111                 :             : {
     112                 :             :     PROP_0,
     113                 :             : //  PROP_ID,            /* Table */
     114                 :             : //  PROP_DATE_OPENED,   /* Table */
     115                 :             : //  PROP_DATE_POSTED,   /* Table */
     116                 :             :     PROP_NOTES,         /* Table */
     117                 :             : //  PROP_ACTIVE,        /* Table */
     118                 :             : //  PROP_CURRENCY,      /* Table */
     119                 :             : //  PROP_OWNER_TYPE,    /* Table */
     120                 :             : //  PROP_OWNER,         /* Table */
     121                 :             : //  PROP_TERMS,         /* Table */
     122                 :             : //  PROP_BILLING_ID,    /* Table */
     123                 :             : //  PROP_POST_TXN,      /* Table */
     124                 :             : //  PROP_POST_LOT,      /* Table */
     125                 :             : //  PROP_POST_ACCOUNT,  /* Table */
     126                 :             : //  PROP_BILLTO_TYPE,   /* Table */
     127                 :             : //  PROP_BILLTO,        /* Table */
     128                 :             : //  PROP_CHARGE_AMOUNT, /* Table, (numeric) */
     129                 :             : };
     130                 :             : 
     131                 :             : /* GObject Initialization */
     132                 :         241 : G_DEFINE_TYPE(GncInvoice, gnc_invoice, QOF_TYPE_INSTANCE)
     133                 :             : 
     134                 :             : static void
     135                 :          86 : gnc_invoice_init (GncInvoice* inv)
     136                 :             : {
     137                 :          86 :     inv->date_posted = INT64_MAX;
     138                 :          86 :     inv->date_opened = INT64_MAX;
     139                 :          86 : }
     140                 :             : 
     141                 :             : static void
     142                 :          26 : gnc_invoice_dispose (GObject *invp)
     143                 :             : {
     144                 :          26 :     G_OBJECT_CLASS(gnc_invoice_parent_class)->dispose(invp);
     145                 :          26 : }
     146                 :             : 
     147                 :             : static void
     148                 :          26 : gnc_invoice_finalize (GObject* invp)
     149                 :             : {
     150                 :          26 :     G_OBJECT_CLASS(gnc_invoice_parent_class)->finalize(invp);
     151                 :          26 : }
     152                 :             : 
     153                 :             : static void
     154                 :           1 : gnc_invoice_get_property (GObject         *object,
     155                 :             :                           guint            prop_id,
     156                 :             :                           GValue          *value,
     157                 :             :                           GParamSpec      *pspec)
     158                 :             : {
     159                 :             :     GncInvoice *inv;
     160                 :             : 
     161                 :           1 :     g_return_if_fail (GNC_IS_INVOICE(object));
     162                 :             : 
     163                 :           1 :     inv = GNC_INVOICE(object);
     164                 :           1 :     switch (prop_id)
     165                 :             :     {
     166                 :           1 :     case PROP_NOTES:
     167                 :           1 :         g_value_set_string (value, inv->notes);
     168                 :           1 :         break;
     169                 :           0 :     default:
     170                 :           0 :         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
     171                 :           0 :         break;
     172                 :             :     }
     173                 :             : }
     174                 :             : 
     175                 :             : static void
     176                 :           1 : gnc_invoice_set_property (GObject         *object,
     177                 :             :                           guint            prop_id,
     178                 :             :                           const GValue    *value,
     179                 :             :                           GParamSpec      *pspec)
     180                 :             : {
     181                 :             :     GncInvoice *inv;
     182                 :             : 
     183                 :           1 :     g_return_if_fail (GNC_IS_INVOICE(object));
     184                 :             : 
     185                 :           1 :     inv = GNC_INVOICE(object);
     186                 :           1 :     g_assert (qof_instance_get_editlevel (inv));
     187                 :             : 
     188                 :           1 :     switch (prop_id)
     189                 :             :     {
     190                 :           1 :     case PROP_NOTES:
     191                 :           1 :         gncInvoiceSetNotes (inv, g_value_get_string (value));
     192                 :           1 :         break;
     193                 :           0 :     default:
     194                 :           0 :         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
     195                 :           0 :         break;
     196                 :             :     }
     197                 :             : }
     198                 :             : 
     199                 :             : /** Returns a string representing this object */
     200                 :             : static gchar*
     201                 :           0 : impl_get_display_name (const QofInstance* inst)
     202                 :             : {
     203                 :             :     GncInvoice* inv;
     204                 :             :     QofInstance* owner;
     205                 :             :     gchar* s;
     206                 :             : 
     207                 :           0 :     g_return_val_if_fail (inst != NULL, FALSE);
     208                 :           0 :     g_return_val_if_fail (GNC_IS_INVOICE(inst), FALSE);
     209                 :             : 
     210                 :           0 :     inv = GNC_INVOICE(inst);
     211                 :           0 :     owner = qofOwnerGetOwner (&inv->owner);
     212                 :           0 :     if (owner != NULL)
     213                 :             :     {
     214                 :             :         gchar* display_name;
     215                 :             : 
     216                 :           0 :         display_name = qof_instance_get_display_name (owner);
     217                 :           0 :         s = g_strdup_printf ("Invoice %s (%s)", inv->id, display_name);
     218                 :           0 :         g_free (display_name);
     219                 :             :     }
     220                 :             :     else
     221                 :             :     {
     222                 :           0 :         s = g_strdup_printf ("Invoice %s", inv->id);
     223                 :             :     }
     224                 :             : 
     225                 :           0 :     return s;
     226                 :             : }
     227                 :             : 
     228                 :             : /** Does this object refer to a specific object */
     229                 :             : static gboolean
     230                 :           0 : impl_refers_to_object (const QofInstance* inst, const QofInstance* ref)
     231                 :             : {
     232                 :             :     GncInvoice* inv;
     233                 :             : 
     234                 :           0 :     g_return_val_if_fail (inst != NULL, FALSE);
     235                 :           0 :     g_return_val_if_fail (GNC_IS_INVOICE(inst), FALSE);
     236                 :             : 
     237                 :           0 :     inv = GNC_INVOICE(inst);
     238                 :             : 
     239                 :           0 :     if (GNC_IS_BILLTERM(ref))
     240                 :             :     {
     241                 :           0 :         return (inv->terms == GNC_BILLTERM(ref));
     242                 :             :     }
     243                 :           0 :     else if (GNC_IS_JOB(ref))
     244                 :             :     {
     245                 :           0 :         return (inv->job == GNC_JOB(ref));
     246                 :             :     }
     247                 :           0 :     else if (GNC_IS_COMMODITY(ref))
     248                 :             :     {
     249                 :           0 :         return (inv->currency == GNC_COMMODITY(ref));
     250                 :             :     }
     251                 :           0 :     else if (GNC_IS_ACCOUNT(ref))
     252                 :             :     {
     253                 :           0 :         return (inv->posted_acc == GNC_ACCOUNT(ref));
     254                 :             :     }
     255                 :           0 :     else if (GNC_IS_TRANSACTION(ref))
     256                 :             :     {
     257                 :           0 :         return (inv->posted_txn == GNC_TRANSACTION(ref));
     258                 :             :     }
     259                 :           0 :     else if (GNC_IS_LOT(ref))
     260                 :             :     {
     261                 :           0 :         return (inv->posted_lot == GNC_LOT(ref));
     262                 :             :     }
     263                 :             : 
     264                 :           0 :     return FALSE;
     265                 :             : }
     266                 :             : 
     267                 :             : /** Returns a list of my type of object which refers to an object.  For example, when called as
     268                 :             :         qof_instance_get_typed_referring_object_list(taxtable, account);
     269                 :             :     it will return the list of taxtables which refer to a specific account.  The result should be the
     270                 :             :     same regardless of which taxtable object is used.  The list must be freed by the caller but the
     271                 :             :     objects on the list must not.
     272                 :             :  */
     273                 :             : static GList*
     274                 :           0 : impl_get_typed_referring_object_list (const QofInstance* inst, const QofInstance* ref)
     275                 :             : {
     276                 :           0 :     if (!GNC_IS_BILLTERM(ref) && !GNC_IS_JOB(ref) && !GNC_IS_COMMODITY(ref) && !GNC_IS_ACCOUNT(ref)
     277                 :           0 :             && !GNC_IS_TRANSACTION(ref) && !GNC_IS_LOT(ref))
     278                 :             :     {
     279                 :           0 :         return NULL;
     280                 :             :     }
     281                 :             : 
     282                 :           0 :     return qof_instance_get_referring_object_list_from_collection (qof_instance_get_collection (inst), ref);
     283                 :             : }
     284                 :             : 
     285                 :             : static void
     286                 :          10 : gnc_invoice_class_init (GncInvoiceClass *klass)
     287                 :             : {
     288                 :          10 :     GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
     289                 :          10 :     QofInstanceClass* qof_class = QOF_INSTANCE_CLASS(klass);
     290                 :             : 
     291                 :          10 :     gobject_class->dispose = gnc_invoice_dispose;
     292                 :          10 :     gobject_class->finalize = gnc_invoice_finalize;
     293                 :          10 :     gobject_class->set_property = gnc_invoice_set_property;
     294                 :          10 :     gobject_class->get_property = gnc_invoice_get_property;
     295                 :             : 
     296                 :          10 :     qof_class->get_display_name = impl_get_display_name;
     297                 :          10 :     qof_class->refers_to_object = impl_refers_to_object;
     298                 :          10 :     qof_class->get_typed_referring_object_list = impl_get_typed_referring_object_list;
     299                 :             : 
     300                 :          10 :     g_object_class_install_property
     301                 :             :     (gobject_class,
     302                 :             :      PROP_NOTES,
     303                 :             :      g_param_spec_string ("notes",
     304                 :             :                           "Invoice Notes",
     305                 :             :                           "The invoice notes is an arbitrary string "
     306                 :             :                           "assigned by the user to provide notes regarding "
     307                 :             :                           "this invoice.",
     308                 :             :                           NULL,
     309                 :             :                           G_PARAM_READWRITE));
     310                 :          10 : }
     311                 :             : 
     312                 :             : /* Create/Destroy Functions */
     313                 :          55 : GncInvoice *gncInvoiceCreate (QofBook *book)
     314                 :             : {
     315                 :             :     GncInvoice *invoice;
     316                 :             : 
     317                 :          55 :     if (!book) return NULL;
     318                 :             : 
     319                 :          55 :     invoice = g_object_new (GNC_TYPE_INVOICE, NULL);
     320                 :          55 :     qof_instance_init_data (&invoice->inst, _GNC_MOD_NAME, book);
     321                 :             : 
     322                 :          55 :     invoice->id = CACHE_INSERT ("");
     323                 :          55 :     invoice->notes = CACHE_INSERT ("");
     324                 :          55 :     invoice->billing_id = CACHE_INSERT ("");
     325                 :             : 
     326                 :          55 :     invoice->billto.type = GNC_OWNER_CUSTOMER;
     327                 :          55 :     invoice->active = TRUE;
     328                 :             : 
     329                 :          55 :     invoice->to_charge_amount = gnc_numeric_zero ();
     330                 :             : 
     331                 :          55 :     qof_event_gen (&invoice->inst, QOF_EVENT_CREATE, NULL);
     332                 :             : 
     333                 :          55 :     return invoice;
     334                 :             : }
     335                 :             : 
     336                 :          31 : GncInvoice *gncInvoiceCopy (const GncInvoice *from)
     337                 :             : {
     338                 :             :     GncInvoice *invoice;
     339                 :             :     QofBook* book;
     340                 :             :     GList *node;
     341                 :          31 :     GValue v = G_VALUE_INIT;
     342                 :             : 
     343                 :          31 :     g_assert (from);
     344                 :          31 :     book = qof_instance_get_book (from);
     345                 :          31 :     g_assert (book);
     346                 :             : 
     347                 :          31 :     invoice = g_object_new (GNC_TYPE_INVOICE, NULL);
     348                 :          31 :     qof_instance_init_data (&invoice->inst, _GNC_MOD_NAME, book);
     349                 :             : 
     350                 :          31 :     gncInvoiceBeginEdit (invoice);
     351                 :             : 
     352                 :          31 :     invoice->id = CACHE_INSERT (from->id);
     353                 :          31 :     invoice->notes = CACHE_INSERT (from->notes);
     354                 :          31 :     invoice->billing_id = CACHE_INSERT (from->billing_id);
     355                 :          31 :     invoice->active = from->active;
     356                 :             : 
     357                 :          31 :     qof_instance_get_kvp (QOF_INSTANCE (from), &v, 1, GNC_INVOICE_IS_CN);
     358                 :          31 :     if (G_VALUE_HOLDS_INT64 (&v))
     359                 :           0 :          qof_instance_set_kvp (QOF_INSTANCE (invoice), &v, 1, GNC_INVOICE_IS_CN);
     360                 :          31 :     g_value_unset (&v);
     361                 :             : 
     362                 :          31 :     invoice->terms = from->terms;
     363                 :          31 :     gncBillTermIncRef (invoice->terms);
     364                 :             : 
     365                 :          31 :     gncOwnerCopy (&from->billto, &invoice->billto);
     366                 :          31 :     gncOwnerCopy (&from->owner, &invoice->owner);
     367                 :          31 :     invoice->job = from->job; // FIXME: Need IncRef or similar here?!?
     368                 :             : 
     369                 :          31 :     invoice->to_charge_amount = from->to_charge_amount;
     370                 :          31 :     invoice->date_opened = from->date_opened;
     371                 :             : 
     372                 :             :     // Oops. Do not forget to copy the pointer to the correct currency here.
     373                 :          31 :     invoice->currency = from->currency;
     374                 :             : 
     375                 :          31 :     gncInvoiceSetDocLink (invoice, gncInvoiceGetDocLink (from));
     376                 :             : 
     377                 :             :     // Copy all invoice->entries
     378                 :          31 :     for (node = from->entries; node; node = node->next)
     379                 :             :     {
     380                 :           0 :         GncEntry *from_entry = node->data;
     381                 :           0 :         GncEntry *to_entry = gncEntryCreate (book);
     382                 :           0 :         gncEntryCopy (from_entry, to_entry, FALSE);
     383                 :             : 
     384                 :           0 :         switch (gncInvoiceGetOwnerType (invoice))
     385                 :             :         {
     386                 :           0 :         case GNC_OWNER_VENDOR:
     387                 :             :         case GNC_OWNER_EMPLOYEE:
     388                 :             :             // this is a vendor bill, or an expense voucher
     389                 :           0 :             gncBillAddEntry (invoice, to_entry);
     390                 :           0 :             break;
     391                 :           0 :         case GNC_OWNER_CUSTOMER:
     392                 :             :         default:
     393                 :             :             // this is an invoice
     394                 :           0 :             gncInvoiceAddEntry (invoice, to_entry);
     395                 :           0 :             break;
     396                 :             :         }
     397                 :             :     }
     398                 :             : 
     399                 :             :     // FIXME: The prices are not (yet) copied; is this a problem?
     400                 :             : 
     401                 :             :     // Posted-date and the posted Txn is intentionally not copied; the
     402                 :             :     // copy isn't "posted" but needs to be posted by the user.
     403                 :          31 :     mark_invoice (invoice);
     404                 :          31 :     gncInvoiceCommitEdit (invoice);
     405                 :             : 
     406                 :          31 :     return invoice;
     407                 :             : }
     408                 :             : 
     409                 :          26 : void gncInvoiceDestroy (GncInvoice *invoice)
     410                 :             : {
     411                 :          26 :     if (!invoice) return;
     412                 :          26 :     qof_instance_set_destroying (invoice, TRUE);
     413                 :          26 :     gncInvoiceCommitEdit (invoice);
     414                 :             : }
     415                 :             : 
     416                 :          26 : static void gncInvoiceFree (GncInvoice *invoice)
     417                 :             : {
     418                 :          26 :     if (!invoice) return;
     419                 :             : 
     420                 :          26 :     qof_event_gen (&invoice->inst, QOF_EVENT_DESTROY, NULL);
     421                 :             : 
     422                 :          26 :     CACHE_REMOVE (invoice->id);
     423                 :          26 :     CACHE_REMOVE (invoice->notes);
     424                 :          26 :     CACHE_REMOVE (invoice->billing_id);
     425                 :          26 :     g_list_free (invoice->entries);
     426                 :          26 :     g_list_free (invoice->prices);
     427                 :             : 
     428                 :          26 :     if (invoice->printname)
     429                 :           0 :         g_free (invoice->printname);
     430                 :             : 
     431                 :          26 :     if (!qof_book_shutting_down (qof_instance_get_book (QOF_INSTANCE(invoice))))
     432                 :             :     {
     433                 :          13 :         if (invoice->terms)
     434                 :           0 :             gncBillTermDecRef (invoice->terms);
     435                 :             :     }
     436                 :             : 
     437                 :             :     /* qof_instance_release (&invoice->inst); */
     438                 :          26 :     g_object_unref (invoice);
     439                 :             : }
     440                 :             : 
     441                 :             : /* ================================================================== */
     442                 :             : /* Set Functions */
     443                 :             : 
     444                 :           9 : void gncInvoiceSetID (GncInvoice *invoice, const char *id)
     445                 :             : {
     446                 :           9 :     if (!invoice || !id) return;
     447                 :           9 :     SET_STR (invoice, invoice->id, id);
     448                 :           9 :     mark_invoice (invoice);
     449                 :           9 :     gncInvoiceCommitEdit (invoice);
     450                 :             : }
     451                 :             : 
     452                 :          42 : void gncInvoiceSetOwner (GncInvoice *invoice, GncOwner *owner)
     453                 :             : {
     454                 :          42 :     if (!invoice || !owner) return;
     455                 :          42 :     if (gncOwnerEqual (&invoice->owner, owner)) return;
     456                 :          42 :     gncInvoiceBeginEdit (invoice);
     457                 :          42 :     gncOwnerCopy (owner, &invoice->owner);
     458                 :          42 :     mark_invoice (invoice);
     459                 :          42 :     gncInvoiceCommitEdit (invoice);
     460                 :             : }
     461                 :             : 
     462                 :             : static void
     463                 :           0 : qofInvoiceSetOwner (GncInvoice *invoice, QofInstance *ent)
     464                 :             : {
     465                 :           0 :     if (!invoice || !ent)
     466                 :             :     {
     467                 :           0 :         return;
     468                 :             :     }
     469                 :           0 :     gncInvoiceBeginEdit (invoice);
     470                 :           0 :     qofOwnerSetEntity (&invoice->owner, ent);
     471                 :           0 :     mark_invoice (invoice);
     472                 :           0 :     gncInvoiceCommitEdit (invoice);
     473                 :             : }
     474                 :             : 
     475                 :             : static void
     476                 :           0 : qofInvoiceSetBillTo (GncInvoice *invoice, QofInstance *ent)
     477                 :             : {
     478                 :           0 :     if (!invoice || !ent)
     479                 :             :     {
     480                 :           0 :         return;
     481                 :             :     }
     482                 :           0 :     gncInvoiceBeginEdit (invoice);
     483                 :           0 :     qofOwnerSetEntity (&invoice->billto, ent);
     484                 :           0 :     mark_invoice (invoice);
     485                 :           0 :     gncInvoiceCommitEdit (invoice);
     486                 :             : }
     487                 :             : 
     488                 :           0 : void gncInvoiceSetDateOpenedGDate (GncInvoice *invoice, const GDate *date)
     489                 :             : {
     490                 :           0 :     g_assert (date);
     491                 :           0 :     gncInvoiceSetDateOpened(invoice, time64CanonicalDayTime (gdate_to_time64 (*date)));
     492                 :           0 : }
     493                 :             : 
     494                 :          14 : void gncInvoiceSetDateOpened (GncInvoice *invoice, time64 date)
     495                 :             : {
     496                 :          14 :     if (!invoice) return;
     497                 :          14 :     if (date == invoice->date_opened) return;
     498                 :          14 :     gncInvoiceBeginEdit (invoice);
     499                 :          14 :     invoice->date_opened = date;
     500                 :          14 :     mark_invoice (invoice);
     501                 :          14 :     gncInvoiceCommitEdit (invoice);
     502                 :             : }
     503                 :             : 
     504                 :          67 : void gncInvoiceSetDatePosted (GncInvoice *invoice, time64 date)
     505                 :             : {
     506                 :          67 :     if (!invoice) return;
     507                 :          67 :     if (date == invoice->date_posted) return;
     508                 :          67 :     gncInvoiceBeginEdit (invoice);
     509                 :          67 :     invoice->date_posted = date;
     510                 :          67 :     mark_invoice (invoice);
     511                 :          67 :     gncInvoiceCommitEdit (invoice);
     512                 :             : }
     513                 :             : 
     514                 :           8 : void gncInvoiceSetTerms (GncInvoice *invoice, GncBillTerm *terms)
     515                 :             : {
     516                 :           8 :     if (!invoice) return;
     517                 :           8 :     if (invoice->terms == terms) return;
     518                 :           8 :     gncInvoiceBeginEdit (invoice);
     519                 :           8 :     if (invoice->terms)
     520                 :           4 :         gncBillTermDecRef (invoice->terms);
     521                 :           8 :     invoice->terms = terms;
     522                 :           8 :     if (invoice->terms)
     523                 :           8 :         gncBillTermIncRef (invoice->terms);
     524                 :           8 :     mark_invoice (invoice);
     525                 :           8 :     gncInvoiceCommitEdit (invoice);
     526                 :             : }
     527                 :             : 
     528                 :          10 : void gncInvoiceSetBillingID (GncInvoice *invoice, const char *billing_id)
     529                 :             : {
     530                 :          10 :     if (!invoice) return;
     531                 :          10 :     SET_STR (invoice, invoice->billing_id, billing_id);
     532                 :           9 :     mark_invoice (invoice);
     533                 :           9 :     gncInvoiceCommitEdit (invoice);
     534                 :             : }
     535                 :             : 
     536                 :          26 : void gncInvoiceSetNotes (GncInvoice *invoice, const char *notes)
     537                 :             : {
     538                 :          26 :     if (!invoice || !notes) return;
     539                 :          26 :     SET_STR (invoice, invoice->notes, notes);
     540                 :          25 :     mark_invoice (invoice);
     541                 :          25 :     gncInvoiceCommitEdit (invoice);
     542                 :             : }
     543                 :             : 
     544                 :          35 : void gncInvoiceSetDocLink (GncInvoice *invoice, const char *doclink)
     545                 :             : {
     546                 :          35 :     if (!invoice || !doclink) return;
     547                 :             : 
     548                 :           3 :     gncInvoiceBeginEdit (invoice);
     549                 :             : 
     550                 :           3 :     if (doclink[0] == '\0')
     551                 :             :     {
     552                 :           1 :         qof_instance_set_kvp (QOF_INSTANCE (invoice), NULL, 1, GNC_INVOICE_DOCLINK);
     553                 :             :     }
     554                 :             :     else
     555                 :             :     {
     556                 :           2 :         GValue v = G_VALUE_INIT;
     557                 :           2 :         g_value_init (&v, G_TYPE_STRING);
     558                 :           2 :         g_value_set_static_string (&v, doclink);
     559                 :           2 :         qof_instance_set_kvp (QOF_INSTANCE (invoice), &v, 1, GNC_INVOICE_DOCLINK);
     560                 :           2 :         g_value_unset (&v);
     561                 :             :     }
     562                 :           3 :     qof_instance_set_dirty (QOF_INSTANCE(invoice));
     563                 :           3 :     gncInvoiceCommitEdit (invoice);
     564                 :             : }
     565                 :             : 
     566                 :           4 : void gncInvoiceSetActive (GncInvoice *invoice, gboolean active)
     567                 :             : {
     568                 :           4 :     if (!invoice) return;
     569                 :           4 :     if (invoice->active == active) return;
     570                 :           0 :     gncInvoiceBeginEdit (invoice);
     571                 :           0 :     invoice->active = active;
     572                 :           0 :     mark_invoice (invoice);
     573                 :           0 :     gncInvoiceCommitEdit (invoice);
     574                 :             : }
     575                 :             : 
     576                 :          16 : void gncInvoiceSetIsCreditNote (GncInvoice *invoice, gboolean credit_note)
     577                 :             : {
     578                 :          16 :      GValue v = G_VALUE_INIT;
     579                 :          16 :     if (!invoice) return;
     580                 :          16 :     gncInvoiceBeginEdit (invoice);
     581                 :          16 :     g_value_init (&v, G_TYPE_INT64);
     582                 :          16 :     g_value_set_int64 (&v, credit_note ? 1 : 0);
     583                 :          16 :     qof_instance_set_kvp (QOF_INSTANCE (invoice), &v, 1, GNC_INVOICE_IS_CN);
     584                 :          16 :     g_value_unset (&v);
     585                 :          16 :     mark_invoice (invoice);
     586                 :          16 :     gncInvoiceCommitEdit (invoice);
     587                 :             : 
     588                 :             :     /* If this is a credit note, set a feature flag for it in the book
     589                 :             :      * This will prevent older GnuCash versions that don't support
     590                 :             :      * credit notes to open this file. */
     591                 :          16 :     if (credit_note)
     592                 :          16 :         gnc_features_set_used (gncInvoiceGetBook (invoice), GNC_FEATURE_CREDIT_NOTES);
     593                 :             : }
     594                 :             : 
     595                 :          56 : void gncInvoiceSetCurrency (GncInvoice *invoice, gnc_commodity *currency)
     596                 :             : {
     597                 :          56 :     if (!invoice || !currency) return;
     598                 :          68 :     if (invoice->currency &&
     599                 :          12 :             gnc_commodity_equal (invoice->currency, currency))
     600                 :          12 :         return;
     601                 :          44 :     gncInvoiceBeginEdit (invoice);
     602                 :          44 :     invoice->currency = currency;
     603                 :          44 :     mark_invoice (invoice);
     604                 :          44 :     gncInvoiceCommitEdit (invoice);
     605                 :             : }
     606                 :             : 
     607                 :           0 : void gncInvoiceSetBillTo (GncInvoice *invoice, GncOwner *billto)
     608                 :             : {
     609                 :           0 :     if (!invoice || !billto) return;
     610                 :           0 :     if (gncOwnerEqual (&invoice->billto, billto)) return;
     611                 :             : 
     612                 :           0 :     gncInvoiceBeginEdit (invoice);
     613                 :           0 :     gncOwnerCopy (billto, &invoice->billto);
     614                 :           0 :     mark_invoice (invoice);
     615                 :           0 :     gncInvoiceCommitEdit (invoice);
     616                 :             : }
     617                 :             : 
     618                 :           1 : void gncInvoiceSetToChargeAmount (GncInvoice *invoice, gnc_numeric amount)
     619                 :             : {
     620                 :           1 :     if (!invoice) return;
     621                 :           1 :     if (gnc_numeric_equal (invoice->to_charge_amount, amount)) return;
     622                 :           0 :     gncInvoiceBeginEdit (invoice);
     623                 :           0 :     invoice->to_charge_amount = amount;
     624                 :           0 :     mark_invoice (invoice);
     625                 :           0 :     gncInvoiceCommitEdit (invoice);
     626                 :             : }
     627                 :             : 
     628                 :          66 : void gncInvoiceSetPostedTxn (GncInvoice *invoice, Transaction *txn)
     629                 :             : {
     630                 :          66 :     if (!invoice) return;
     631                 :          66 :     g_return_if_fail (invoice->posted_txn == NULL);
     632                 :             : 
     633                 :          66 :     gncInvoiceBeginEdit (invoice);
     634                 :          66 :     invoice->posted_txn = txn;
     635                 :          66 :     mark_invoice (invoice);
     636                 :          66 :     gncInvoiceCommitEdit (invoice);
     637                 :             : }
     638                 :             : 
     639                 :          66 : void gncInvoiceSetPostedLot (GncInvoice *invoice, GNCLot *lot)
     640                 :             : {
     641                 :          66 :     if (!invoice) return;
     642                 :          66 :     g_return_if_fail (invoice->posted_lot == NULL);
     643                 :             : 
     644                 :          66 :     gncInvoiceBeginEdit (invoice);
     645                 :          66 :     invoice->posted_lot = lot;
     646                 :          66 :     mark_invoice (invoice);
     647                 :          66 :     gncInvoiceCommitEdit (invoice);
     648                 :             : }
     649                 :             : 
     650                 :          66 : void gncInvoiceSetPostedAcc (GncInvoice *invoice, Account *acc)
     651                 :             : {
     652                 :          66 :     if (!invoice) return;
     653                 :          66 :     g_return_if_fail (invoice->posted_acc == NULL);
     654                 :             : 
     655                 :          66 :     gncInvoiceBeginEdit (invoice);
     656                 :          66 :     invoice->posted_acc = acc;
     657                 :          66 :     mark_invoice (invoice);
     658                 :          66 :     gncInvoiceCommitEdit (invoice);
     659                 :             : }
     660                 :             : 
     661                 :          91 : void gncInvoiceAddEntry (GncInvoice *invoice, GncEntry *entry)
     662                 :             : {
     663                 :             :     GncInvoice *old;
     664                 :             : 
     665                 :          91 :     g_assert (invoice);
     666                 :          91 :     g_assert (entry);
     667                 :          91 :     if (!invoice || !entry) return;
     668                 :             : 
     669                 :          91 :     old = gncEntryGetInvoice (entry);
     670                 :          91 :     if (old == invoice) return; /* I already own this one */
     671                 :          91 :     if (old) gncInvoiceRemoveEntry (old, entry);
     672                 :             : 
     673                 :          91 :     gncInvoiceBeginEdit (invoice);
     674                 :          91 :     gncEntrySetInvoice (entry, invoice);
     675                 :          91 :     invoice->entries = g_list_insert_sorted (invoice->entries, entry,
     676                 :             :                        (GCompareFunc)gncEntryCompare);
     677                 :          91 :     mark_invoice (invoice);
     678                 :          91 :     gncInvoiceCommitEdit (invoice);
     679                 :             : }
     680                 :             : 
     681                 :           7 : void gncInvoiceRemoveEntry (GncInvoice *invoice, GncEntry *entry)
     682                 :             : {
     683                 :           7 :     if (!invoice || !entry) return;
     684                 :             : 
     685                 :           7 :     gncInvoiceBeginEdit (invoice);
     686                 :           7 :     gncEntrySetInvoice (entry, NULL);
     687                 :           7 :     invoice->entries = g_list_remove (invoice->entries, entry);
     688                 :           7 :     mark_invoice (invoice);
     689                 :           7 :     gncInvoiceCommitEdit (invoice);
     690                 :             : }
     691                 :             : 
     692                 :           0 : void gncInvoiceAddPrice (GncInvoice *invoice, GNCPrice *price)
     693                 :             : {
     694                 :             :     GList *node;
     695                 :             :     gnc_commodity *commodity;
     696                 :             : 
     697                 :           0 :     if (!invoice || !price) return;
     698                 :             : 
     699                 :             :     /* Keep only one price per commodity per invoice
     700                 :             :      * So if a price was set previously remove it first */
     701                 :           0 :     node = g_list_first (invoice->prices);
     702                 :           0 :     commodity = gnc_price_get_commodity (price);
     703                 :           0 :     while (node != NULL)
     704                 :             :     {
     705                 :           0 :         GNCPrice *curr = (GNCPrice*)node->data;
     706                 :           0 :         if (gnc_commodity_equal (commodity, gnc_price_get_commodity (curr)))
     707                 :           0 :             break;
     708                 :           0 :         node = g_list_next (node);
     709                 :             :     }
     710                 :             : 
     711                 :           0 :     gncInvoiceBeginEdit (invoice);
     712                 :           0 :     if (node)
     713                 :           0 :         invoice->prices = g_list_delete_link (invoice->prices, node);
     714                 :           0 :     invoice->prices = g_list_prepend (invoice->prices, price);
     715                 :           0 :     mark_invoice (invoice);
     716                 :           0 :     gncInvoiceCommitEdit (invoice);
     717                 :             : }
     718                 :             : 
     719                 :           5 : void gncBillAddEntry (GncInvoice *bill, GncEntry *entry)
     720                 :             : {
     721                 :             :     GncInvoice *old;
     722                 :             : 
     723                 :           5 :     g_assert (bill);
     724                 :           5 :     g_assert (entry);
     725                 :           5 :     if (!bill || !entry) return;
     726                 :             : 
     727                 :           5 :     old = gncEntryGetBill (entry);
     728                 :           5 :     if (old == bill) return;    /* I already own this one */
     729                 :           5 :     if (old) gncBillRemoveEntry (old, entry);
     730                 :             : 
     731                 :           5 :     gncInvoiceBeginEdit (bill);
     732                 :           5 :     gncEntrySetBill (entry, bill);
     733                 :           5 :     bill->entries = g_list_insert_sorted (bill->entries, entry,
     734                 :             :                                           (GCompareFunc)gncEntryCompare);
     735                 :           5 :     mark_invoice (bill);
     736                 :           5 :     gncInvoiceCommitEdit (bill);
     737                 :             : }
     738                 :             : 
     739                 :           0 : void gncBillRemoveEntry (GncInvoice *bill, GncEntry *entry)
     740                 :             : {
     741                 :           0 :     if (!bill || !entry) return;
     742                 :             : 
     743                 :           0 :     gncInvoiceBeginEdit (bill);
     744                 :           0 :     gncEntrySetBill (entry, NULL);
     745                 :           0 :     bill->entries = g_list_remove (bill->entries, entry);
     746                 :           0 :     mark_invoice (bill);
     747                 :           0 :     gncInvoiceCommitEdit (bill);
     748                 :             : }
     749                 :             : 
     750                 :           0 : void gncInvoiceSortEntries (GncInvoice *invoice)
     751                 :             : {
     752                 :           0 :     if (!invoice) return;
     753                 :           0 :     invoice->entries = g_list_sort (invoice->entries,
     754                 :             :                                    (GCompareFunc)gncEntryCompare);
     755                 :           0 :     gncInvoiceBeginEdit (invoice);
     756                 :           0 :     mark_invoice (invoice);
     757                 :           0 :     gncInvoiceCommitEdit (invoice);
     758                 :             : }
     759                 :             : 
     760                 :           7 : void gncInvoiceRemoveEntries (GncInvoice *invoice)
     761                 :             : {
     762                 :           7 :     if (!invoice) return;
     763                 :             : 
     764                 :             :     // gnc{Bill,Invoice}RemoveEntry free the "entry" node.
     765                 :             :     // Make sure to save "next" first.
     766                 :          14 :     for (GList *next, *node = invoice->entries; node; node = next)
     767                 :             :     {
     768                 :           7 :         next = node->next;
     769                 :           7 :         GncEntry *entry = node->data;
     770                 :             : 
     771                 :           7 :         switch (gncInvoiceGetOwnerType (invoice))
     772                 :             :         {
     773                 :           0 :         case GNC_OWNER_VENDOR:
     774                 :             :         case GNC_OWNER_EMPLOYEE:
     775                 :             :             // this is a vendor bill, or an expense voucher
     776                 :           0 :             gncBillRemoveEntry (invoice, entry);
     777                 :           0 :             break;
     778                 :           7 :         case GNC_OWNER_CUSTOMER:
     779                 :             :         default:
     780                 :             :             // this is an invoice
     781                 :           7 :             gncInvoiceRemoveEntry (invoice, entry);
     782                 :           7 :             break;
     783                 :             :         }
     784                 :             : 
     785                 :             :         /* If the entry is no longer referenced by any document,
     786                 :             :          * remove it.
     787                 :             :          */
     788                 :          20 :         if (!(gncEntryGetInvoice (entry) ||
     789                 :           7 :               gncEntryGetBill (entry) ||
     790                 :           6 :               gncEntryGetOrder (entry)))
     791                 :             :         {
     792                 :           6 :             gncEntryBeginEdit (entry);
     793                 :           6 :             gncEntryDestroy (entry);
     794                 :             :         }
     795                 :             :     }
     796                 :             : }
     797                 :             : 
     798                 :             : /* ================================================================== */
     799                 :             : /* Get Functions */
     800                 :             : 
     801                 :         321 : const char * gncInvoiceGetID (const GncInvoice *invoice)
     802                 :             : {
     803                 :         321 :     if (!invoice) return NULL;
     804                 :         321 :     return invoice->id;
     805                 :             : }
     806                 :             : 
     807                 :        2651 : const GncOwner * gncInvoiceGetOwner (const GncInvoice *invoice)
     808                 :             : {
     809                 :        2651 :     if (!invoice) return NULL;
     810                 :        1811 :     return &invoice->owner;
     811                 :             : }
     812                 :             : 
     813                 :           0 : static QofInstance * qofInvoiceGetOwner (GncInvoice *invoice)
     814                 :             : {
     815                 :             :     GncOwner *owner;
     816                 :             : 
     817                 :           0 :     if (!invoice)
     818                 :             :     {
     819                 :           0 :         return NULL;
     820                 :             :     }
     821                 :           0 :     owner = &invoice->owner;
     822                 :           0 :     return QOF_INSTANCE(owner);
     823                 :             : }
     824                 :             : 
     825                 :           0 : static QofInstance * qofInvoiceGetBillTo (GncInvoice *invoice)
     826                 :             : {
     827                 :             :     GncOwner *billto;
     828                 :             : 
     829                 :           0 :     if (!invoice)
     830                 :             :     {
     831                 :           0 :         return NULL;
     832                 :             :     }
     833                 :           0 :     billto = &invoice->billto;
     834                 :           0 :     return QOF_INSTANCE(billto);
     835                 :             : }
     836                 :             : 
     837                 :          11 : time64 gncInvoiceGetDateOpened (const GncInvoice *invoice)
     838                 :             : {
     839                 :          11 :     if (!invoice) return INT64_MAX;
     840                 :          11 :     return invoice->date_opened;
     841                 :             : }
     842                 :             : 
     843                 :          97 : time64 gncInvoiceGetDatePosted (const GncInvoice *invoice)
     844                 :             : {
     845                 :          97 :     if (!invoice) return INT64_MAX;
     846                 :          97 :     return invoice->date_posted;
     847                 :             : }
     848                 :             : 
     849                 :          80 : time64 gncInvoiceGetDateDue (const GncInvoice *invoice)
     850                 :             : {
     851                 :             :     Transaction *txn;
     852                 :          80 :     if (!invoice) return INT64_MAX;
     853                 :          80 :     txn = gncInvoiceGetPostedTxn (invoice);
     854                 :          80 :     if (!txn) return INT64_MAX;
     855                 :          80 :     return xaccTransRetDateDue (txn);
     856                 :             : }
     857                 :             : 
     858                 :          30 : GncBillTerm * gncInvoiceGetTerms (const GncInvoice *invoice)
     859                 :             : {
     860                 :          30 :     if (!invoice) return NULL;
     861                 :          30 :     return invoice->terms;
     862                 :             : }
     863                 :             : 
     864                 :          27 : const char * gncInvoiceGetBillingID (const GncInvoice *invoice)
     865                 :             : {
     866                 :          27 :     if (!invoice) return NULL;
     867                 :          27 :     return invoice->billing_id;
     868                 :             : }
     869                 :             : 
     870                 :          70 : const char * gncInvoiceGetNotes (const GncInvoice *invoice)
     871                 :             : {
     872                 :          70 :     if (!invoice) return NULL;
     873                 :          70 :     return invoice->notes;
     874                 :             : }
     875                 :             : 
     876                 :          48 : const char * gncInvoiceGetDocLink (const GncInvoice *invoice)
     877                 :             : {
     878                 :          48 :     if (!invoice) return NULL;
     879                 :             : 
     880                 :          48 :     GValue v = G_VALUE_INIT;
     881                 :          48 :     qof_instance_get_kvp (QOF_INSTANCE(invoice), &v, 1, GNC_INVOICE_DOCLINK);
     882                 :          48 :     const char *rv = G_VALUE_HOLDS_STRING(&v) ? g_value_get_string (&v) : NULL;
     883                 :          48 :     g_value_unset (&v);
     884                 :             : 
     885                 :          48 :     return rv;
     886                 :             : }
     887                 :             : 
     888                 :         678 : GncOwnerType gncInvoiceGetOwnerType (const GncInvoice *invoice)
     889                 :             : {
     890                 :             :     const GncOwner *owner;
     891                 :         678 :     g_return_val_if_fail (invoice, GNC_OWNER_NONE);
     892                 :             : 
     893                 :         678 :     owner = gncOwnerGetEndOwner (gncInvoiceGetOwner (invoice));
     894                 :         678 :     return (gncOwnerGetType (owner));
     895                 :             : }
     896                 :             : 
     897                 :         209 : static gnc_numeric gncInvoiceSumTaxesInternal (AccountValueList *taxes)
     898                 :             : {
     899                 :         209 :     gnc_numeric tt = gnc_numeric_zero ();
     900                 :             : 
     901                 :         209 :     if (taxes)
     902                 :             :     {
     903                 :             :         GList *node;
     904                 :             :         // Note we can use GNC_DENOM_AUTO below for rounding because
     905                 :             :         // the values passed to this function should already have been rounded
     906                 :             :         // to the desired denom and addition will just preserve it in that case.
     907                 :          32 :         for (node = taxes; node; node=node->next)
     908                 :             :         {
     909                 :          16 :             GncAccountValue *acc_val = node->data;
     910                 :          16 :             tt = gnc_numeric_add (tt, acc_val->value, GNC_DENOM_AUTO,
     911                 :             :                                   GNC_HOW_DENOM_EXACT | GNC_HOW_RND_ROUND_HALF_UP);
     912                 :             :         }
     913                 :             :     }
     914                 :         209 :     return tt;
     915                 :             : }
     916                 :             : 
     917                 :         353 : static gnc_numeric gncInvoiceGetNetAndTaxesInternal (GncInvoice *invoice, gboolean use_value,
     918                 :             :                                                      AccountValueList **taxes,
     919                 :             :                                                      gboolean use_payment_type,
     920                 :             :                                                      GncEntryPaymentType type)
     921                 :             : {
     922                 :             :     GList *node;
     923                 :         353 :     gnc_numeric net_total = gnc_numeric_zero ();
     924                 :             :     gboolean is_cust_doc, is_cn;
     925                 :         353 :     AccountValueList *tv_list = NULL;
     926                 :         353 :     int denom = gnc_commodity_get_fraction (gncInvoiceGetCurrency (invoice));
     927                 :             : 
     928                 :         353 :     g_return_val_if_fail (invoice, net_total);
     929                 :             : 
     930                 :         353 :     ENTER ("");
     931                 :             :     /* Is the current document an invoice/credit note related to a customer or a vendor/employee ?
     932                 :             :      * The GncEntry code needs to know to return the proper entry amounts
     933                 :             :      */
     934                 :         353 :     is_cust_doc = (gncInvoiceGetOwnerType (invoice) == GNC_OWNER_CUSTOMER);
     935                 :         353 :     is_cn = gncInvoiceGetIsCreditNote (invoice);
     936                 :             : 
     937                 :             : 
     938                 :         893 :     for (node = gncInvoiceGetEntries (invoice); node; node = node->next)
     939                 :             :     {
     940                 :         540 :         GncEntry *entry = node->data;
     941                 :             :         gnc_numeric value;
     942                 :             : 
     943                 :         540 :         if (use_payment_type && gncEntryGetBillPayment (entry) != type)
     944                 :           0 :             continue;
     945                 :             : 
     946                 :         540 :         if (use_value)
     947                 :             :         {
     948                 :             :             // Always use rounded net values to prevent creating imbalanced transactions on posting
     949                 :             :             // https://bugs.gnucash.org/show_bug.cgi?id=628903
     950                 :         362 :             value = gncEntryGetDocValue (entry, TRUE, is_cust_doc, is_cn);
     951                 :         362 :             if (gnc_numeric_check (value) == GNC_ERROR_OK)
     952                 :         362 :                 net_total = gnc_numeric_add (net_total, value, GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD);
     953                 :             :             else
     954                 :           0 :                 PWARN ("bad value in our entry");
     955                 :             :         }
     956                 :             : 
     957                 :         540 :         if (taxes)
     958                 :             :         {
     959                 :         456 :             AccountValueList *entrytaxes = gncEntryGetDocTaxValues (entry, is_cust_doc, is_cn);
     960                 :         456 :             tv_list = gncAccountValueAddList (tv_list, entrytaxes);
     961                 :         456 :             gncAccountValueDestroy (entrytaxes);
     962                 :             :         }
     963                 :             :     }
     964                 :             : 
     965                 :         353 :     if (taxes)
     966                 :             :     {
     967                 :             :         GList *node;
     968                 :             :         // Round tax totals (accumulated per tax account) to prevent creating imbalanced transactions on posting
     969                 :             :         // which could otherwise happen when using a tax table with multiple tax rates
     970                 :         320 :         for (node = tv_list; node; node=node->next)
     971                 :             :         {
     972                 :          23 :             GncAccountValue *acc_val = node->data;
     973                 :          23 :             acc_val->value = gnc_numeric_convert (acc_val->value,
     974                 :             :                                   denom, GNC_HOW_DENOM_EXACT | GNC_HOW_RND_ROUND_HALF_UP);
     975                 :             :         }
     976                 :         297 :         *taxes = tv_list;
     977                 :             :     }
     978                 :             : 
     979                 :         353 :     LEAVE ("%" PRId64 "/%" PRId64, net_total.num, net_total.denom);
     980                 :         353 :     return net_total;
     981                 :             : }
     982                 :             : 
     983                 :         265 : static gnc_numeric gncInvoiceGetTotalInternal (GncInvoice *invoice, gboolean use_value,
     984                 :             :                                                gboolean use_tax,
     985                 :             :                                                gboolean use_payment_type, GncEntryPaymentType type)
     986                 :             : {
     987                 :             :     AccountValueList *taxes;
     988                 :             :     gnc_numeric total;
     989                 :             : 
     990                 :         265 :     if (!invoice) return gnc_numeric_zero ();
     991                 :             : 
     992                 :         265 :     ENTER ("");
     993                 :         265 :     total = gncInvoiceGetNetAndTaxesInternal (invoice, use_value, use_tax? &taxes : NULL, use_payment_type, type);
     994                 :             : 
     995                 :         265 :     if (use_tax)
     996                 :             :     {
     997                 :             :         // Note we can use GNC_DENOM_AUTO below for rounding because
     998                 :             :         // the values passed to this function should already have been rounded
     999                 :             :         // to the desired denom and addition will just preserve it in that case.
    1000                 :         209 :         total = gnc_numeric_add (total, gncInvoiceSumTaxesInternal (taxes),
    1001                 :             :                                  GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT | GNC_HOW_RND_ROUND_HALF_UP);
    1002                 :         209 :         gncAccountValueDestroy (taxes);
    1003                 :             :     }
    1004                 :         265 :     LEAVE ("%" PRId64 "/%" PRId64, total.num, total.denom);
    1005                 :         265 :     return total;
    1006                 :             : }
    1007                 :             : 
    1008                 :         174 : gnc_numeric gncInvoiceGetTotal (GncInvoice *invoice)
    1009                 :             : {
    1010                 :         174 :     if (!invoice) return gnc_numeric_zero ();
    1011                 :         174 :     return gncInvoiceGetTotalInternal (invoice, TRUE, TRUE, FALSE, 0);
    1012                 :             : }
    1013                 :             : 
    1014                 :          56 : gnc_numeric gncInvoiceGetTotalSubtotal (GncInvoice *invoice)
    1015                 :             : {
    1016                 :          56 :     if (!invoice) return gnc_numeric_zero ();
    1017                 :          56 :     return gncInvoiceGetTotalInternal (invoice, TRUE, FALSE, FALSE, 0);
    1018                 :             : }
    1019                 :             : 
    1020                 :          35 : gnc_numeric gncInvoiceGetTotalTax (GncInvoice *invoice)
    1021                 :             : {
    1022                 :          35 :     if (!invoice) return gnc_numeric_zero ();
    1023                 :          35 :     return gncInvoiceGetTotalInternal (invoice, FALSE, TRUE, FALSE, 0);
    1024                 :             : }
    1025                 :             : 
    1026                 :           0 : gnc_numeric gncInvoiceGetTotalOf (GncInvoice *invoice, GncEntryPaymentType type)
    1027                 :             : {
    1028                 :           0 :     if (!invoice) return gnc_numeric_zero ();
    1029                 :           0 :     return gncInvoiceGetTotalInternal (invoice, TRUE, TRUE, TRUE, type);
    1030                 :             : }
    1031                 :             : 
    1032                 :          88 : AccountValueList *gncInvoiceGetTotalTaxList (GncInvoice *invoice)
    1033                 :             : {
    1034                 :             :     AccountValueList *taxes;
    1035                 :          88 :     if (!invoice) return NULL;
    1036                 :             : 
    1037                 :          88 :     gncInvoiceGetNetAndTaxesInternal (invoice, FALSE, &taxes, FALSE, 0);
    1038                 :          88 :     return taxes;
    1039                 :             : }
    1040                 :             : 
    1041                 :           0 : GList * gncInvoiceGetTypeListForOwnerType (GncOwnerType type)
    1042                 :             : {
    1043                 :           0 :     GList *type_list = NULL;
    1044                 :           0 :     switch (type)
    1045                 :             :     {
    1046                 :           0 :     case GNC_OWNER_CUSTOMER:
    1047                 :           0 :         type_list = g_list_append (type_list, GINT_TO_POINTER(GNC_INVOICE_CUST_INVOICE));
    1048                 :           0 :         type_list = g_list_append (type_list, GINT_TO_POINTER(GNC_INVOICE_CUST_CREDIT_NOTE));
    1049                 :           0 :         return type_list;
    1050                 :           0 :     case GNC_OWNER_VENDOR:
    1051                 :           0 :         type_list = g_list_append (type_list, GINT_TO_POINTER(GNC_INVOICE_VEND_INVOICE));
    1052                 :           0 :         type_list = g_list_append (type_list, GINT_TO_POINTER(GNC_INVOICE_VEND_CREDIT_NOTE));
    1053                 :           0 :         return type_list;
    1054                 :           0 :     case GNC_OWNER_EMPLOYEE:
    1055                 :           0 :         type_list = g_list_append (type_list, GINT_TO_POINTER(GNC_INVOICE_EMPL_INVOICE));
    1056                 :           0 :         type_list = g_list_append (type_list, GINT_TO_POINTER(GNC_INVOICE_EMPL_CREDIT_NOTE));
    1057                 :           0 :         return type_list;
    1058                 :           0 :     default:
    1059                 :           0 :         PWARN("Bad owner type, no invoices.");
    1060                 :           0 :         return NULL;
    1061                 :             :     }
    1062                 :             : 
    1063                 :             : }
    1064                 :             : 
    1065                 :         182 : GncInvoiceType gncInvoiceGetType (const GncInvoice *invoice)
    1066                 :             : {
    1067                 :         182 :     if (!invoice) return GNC_INVOICE_UNDEFINED;
    1068                 :         182 :     switch (gncInvoiceGetOwnerType (invoice))
    1069                 :             :     {
    1070                 :         126 :     case GNC_OWNER_CUSTOMER:
    1071                 :         126 :         return (gncInvoiceGetIsCreditNote (invoice) ?
    1072                 :         126 :                 GNC_INVOICE_CUST_CREDIT_NOTE :
    1073                 :             :                 GNC_INVOICE_CUST_INVOICE);
    1074                 :          28 :     case GNC_OWNER_VENDOR:
    1075                 :          28 :         return (gncInvoiceGetIsCreditNote (invoice) ?
    1076                 :          28 :                 GNC_INVOICE_VEND_CREDIT_NOTE :
    1077                 :             :                 GNC_INVOICE_VEND_INVOICE);
    1078                 :          28 :     case GNC_OWNER_EMPLOYEE:
    1079                 :          28 :         return (gncInvoiceGetIsCreditNote (invoice) ?
    1080                 :          28 :                 GNC_INVOICE_EMPL_CREDIT_NOTE :
    1081                 :             :                 GNC_INVOICE_EMPL_INVOICE);
    1082                 :           0 :     default:
    1083                 :           0 :         PWARN ("No invoice types defined for owner %d",
    1084                 :             :                gncInvoiceGetOwnerType (invoice));
    1085                 :           0 :         return GNC_INVOICE_UNDEFINED;
    1086                 :             :     }
    1087                 :             : }
    1088                 :             : 
    1089                 :         128 : const char * gncInvoiceGetTypeString (const GncInvoice *invoice)
    1090                 :             : {
    1091                 :         128 :     GncInvoiceType type = gncInvoiceGetType (invoice);
    1092                 :         128 :     switch (type)
    1093                 :             :     {
    1094                 :          79 :     case GNC_INVOICE_CUST_INVOICE:
    1095                 :          79 :         return _("Invoice");
    1096                 :           8 :     case GNC_INVOICE_VEND_INVOICE:
    1097                 :           8 :         return _("Bill");
    1098                 :           8 :     case GNC_INVOICE_EMPL_INVOICE:
    1099                 :           8 :         return _("Expense");
    1100                 :          33 :     case GNC_INVOICE_CUST_CREDIT_NOTE:
    1101                 :             :     case GNC_INVOICE_VEND_CREDIT_NOTE:
    1102                 :             :     case GNC_INVOICE_EMPL_CREDIT_NOTE:
    1103                 :          33 :         return _("Credit Note");
    1104                 :           0 :     default:
    1105                 :           0 :         PWARN("Unknown invoice type");
    1106                 :           0 :         return NULL;
    1107                 :             :     }
    1108                 :             : }
    1109                 :             : 
    1110                 :         580 : gnc_commodity * gncInvoiceGetCurrency (const GncInvoice *invoice)
    1111                 :             : {
    1112                 :         580 :     if (!invoice) return NULL;
    1113                 :         580 :     return invoice->currency;
    1114                 :             : }
    1115                 :             : 
    1116                 :         903 : GncOwner * gncInvoiceGetBillTo (GncInvoice *invoice)
    1117                 :             : {
    1118                 :         903 :     if (!invoice) return NULL;
    1119                 :         105 :     return &invoice->billto;
    1120                 :             : }
    1121                 :             : 
    1122                 :         113 : GNCLot * gncInvoiceGetPostedLot (const GncInvoice *invoice)
    1123                 :             : {
    1124                 :         113 :     if (!invoice) return NULL;
    1125                 :         113 :     return invoice->posted_lot;
    1126                 :             : }
    1127                 :             : 
    1128                 :         299 : Transaction * gncInvoiceGetPostedTxn (const GncInvoice *invoice)
    1129                 :             : {
    1130                 :         299 :     if (!invoice) return NULL;
    1131                 :         293 :     return invoice->posted_txn;
    1132                 :             : }
    1133                 :             : 
    1134                 :          56 : Account * gncInvoiceGetPostedAcc (const GncInvoice *invoice)
    1135                 :             : {
    1136                 :          56 :     if (!invoice) return NULL;
    1137                 :          56 :     return invoice->posted_acc;
    1138                 :             : }
    1139                 :             : 
    1140                 :           4 : gboolean gncInvoiceGetActive (const GncInvoice *invoice)
    1141                 :             : {
    1142                 :           4 :     if (!invoice) return FALSE;
    1143                 :           4 :     return invoice->active;
    1144                 :             : }
    1145                 :             : 
    1146                 :         648 : gboolean gncInvoiceGetIsCreditNote (const GncInvoice *invoice)
    1147                 :             : {
    1148                 :         648 :     GValue v = G_VALUE_INIT;
    1149                 :             :     gboolean retval;
    1150                 :         648 :     if (!invoice) return FALSE;
    1151                 :         648 :     qof_instance_get_kvp (QOF_INSTANCE(invoice), &v, 1, GNC_INVOICE_IS_CN);
    1152                 :         648 :     retval = G_VALUE_HOLDS_INT64(&v) && g_value_get_int64 (&v);
    1153                 :         648 :     g_value_unset (&v);
    1154                 :         648 :     return retval;
    1155                 :             : }
    1156                 :             : 
    1157                 :             : 
    1158                 :           3 : gnc_numeric gncInvoiceGetToChargeAmount (const GncInvoice *invoice)
    1159                 :             : {
    1160                 :           3 :     if (!invoice) return gnc_numeric_zero ();
    1161                 :           3 :     return invoice->to_charge_amount;
    1162                 :             : }
    1163                 :             : 
    1164                 :         484 : EntryList * gncInvoiceGetEntries (GncInvoice *invoice)
    1165                 :             : {
    1166                 :         484 :     if (!invoice) return NULL;
    1167                 :         484 :     return invoice->entries;
    1168                 :             : }
    1169                 :             : 
    1170                 :           0 : GNCPrice * gncInvoiceGetPrice (GncInvoice *invoice, gnc_commodity *commodity)
    1171                 :             : {
    1172                 :           0 :     GList *node = g_list_first (invoice->prices);
    1173                 :             : 
    1174                 :           0 :     while (node != NULL)
    1175                 :             :     {
    1176                 :           0 :         GNCPrice *curr = (GNCPrice*)node->data;
    1177                 :             : 
    1178                 :           0 :         if (gnc_commodity_equal (commodity, gnc_price_get_commodity (curr)))
    1179                 :           0 :             return curr;
    1180                 :             : 
    1181                 :           0 :         node = g_list_next (node);
    1182                 :             :     }
    1183                 :             : 
    1184                 :           0 :     return NULL;
    1185                 :             : }
    1186                 :             : 
    1187                 :             : static QofCollection*
    1188                 :           0 : qofInvoiceGetEntries (GncInvoice *invoice)
    1189                 :             : {
    1190                 :             :     QofCollection *entry_coll;
    1191                 :             :     GList         *list;
    1192                 :             :     QofInstance     *entry;
    1193                 :             : 
    1194                 :           0 :     entry_coll = qof_collection_new (GNC_ID_ENTRY);
    1195                 :           0 :     for (list = gncInvoiceGetEntries (invoice); list != NULL; list = list->next)
    1196                 :             :     {
    1197                 :           0 :         entry = QOF_INSTANCE(list->data);
    1198                 :           0 :         qof_collection_add_entity (entry_coll, entry);
    1199                 :             :     }
    1200                 :           0 :     return entry_coll;
    1201                 :             : }
    1202                 :             : 
    1203                 :             : static void
    1204                 :           0 : qofInvoiceEntryCB (QofInstance *ent, gpointer user_data)
    1205                 :             : {
    1206                 :             :     GncInvoice *invoice;
    1207                 :             : 
    1208                 :           0 :     invoice = (GncInvoice*)user_data;
    1209                 :           0 :     if (!invoice || !ent)
    1210                 :             :     {
    1211                 :           0 :         return;
    1212                 :             :     }
    1213                 :           0 :     switch (gncInvoiceGetOwnerType (invoice))
    1214                 :             :     {
    1215                 :           0 :     case GNC_OWNER_VENDOR:
    1216                 :             :     {
    1217                 :           0 :         gncBillAddEntry (invoice, (GncEntry*) ent);
    1218                 :           0 :         break;
    1219                 :             :     }
    1220                 :           0 :     default :
    1221                 :             :     {
    1222                 :           0 :         gncInvoiceAddEntry (invoice, (GncEntry*)ent);
    1223                 :           0 :         break;
    1224                 :             :     }
    1225                 :             :     }
    1226                 :             : }
    1227                 :             : 
    1228                 :             : static void
    1229                 :           0 : qofInvoiceSetEntries (GncInvoice *invoice, QofCollection *entry_coll)
    1230                 :             : {
    1231                 :           0 :     if (!entry_coll)
    1232                 :             :     {
    1233                 :           0 :         return;
    1234                 :             :     }
    1235                 :           0 :     if (0 == g_strcmp0 (qof_collection_get_type (entry_coll), GNC_ID_ENTRY))
    1236                 :             :     {
    1237                 :           0 :         qof_collection_foreach (entry_coll, qofInvoiceEntryCB, invoice);
    1238                 :             :     }
    1239                 :             : }
    1240                 :             : 
    1241                 :             : static GncJob*
    1242                 :           0 : qofInvoiceGetJob (const GncInvoice *invoice)
    1243                 :             : {
    1244                 :           0 :     if (!invoice)
    1245                 :             :     {
    1246                 :           0 :         return NULL;
    1247                 :             :     }
    1248                 :           0 :     return invoice->job;
    1249                 :             : }
    1250                 :             : 
    1251                 :             : static void
    1252                 :           0 : qofInvoiceSetJob (GncInvoice *invoice, GncJob *job)
    1253                 :             : {
    1254                 :           0 :     if (!invoice)
    1255                 :             :     {
    1256                 :           0 :         return;
    1257                 :             :     }
    1258                 :           0 :     invoice->job = job;
    1259                 :             : }
    1260                 :             : 
    1261                 :             : void
    1262                 :           8 : gncInvoiceDetachFromLot (GNCLot *lot)
    1263                 :             : {
    1264                 :           8 :     if (!lot) return;
    1265                 :             : 
    1266                 :           8 :     gnc_lot_begin_edit (lot);
    1267                 :           8 :     qof_instance_set (QOF_INSTANCE (lot), "invoice", NULL, NULL);
    1268                 :           8 :     gnc_lot_commit_edit (lot);
    1269                 :           8 :     gnc_lot_set_cached_invoice (lot, NULL);
    1270                 :             : }
    1271                 :             : 
    1272                 :             : void
    1273                 :          64 : gncInvoiceAttachToLot (GncInvoice *invoice, GNCLot *lot)
    1274                 :             : {
    1275                 :             :     GncGUID *guid;
    1276                 :          64 :     if (!invoice || !lot)
    1277                 :           0 :         return;
    1278                 :             : 
    1279                 :          64 :     if (invoice->posted_lot) return;    /* Cannot reset invoice's lot */
    1280                 :          64 :     guid  = (GncGUID*)qof_instance_get_guid (QOF_INSTANCE(invoice));
    1281                 :          64 :     gnc_lot_begin_edit (lot);
    1282                 :          64 :     qof_instance_set (QOF_INSTANCE (lot), "invoice", guid, NULL);
    1283                 :          64 :     gnc_lot_commit_edit (lot);
    1284                 :          64 :     gnc_lot_set_cached_invoice (lot, invoice);
    1285                 :          64 :     gncInvoiceSetPostedLot (invoice, lot);
    1286                 :             : }
    1287                 :             : 
    1288                 :        1406 : GncInvoice * gncInvoiceGetInvoiceFromLot (GNCLot *lot)
    1289                 :             : {
    1290                 :        1406 :     GncGUID *guid = NULL;
    1291                 :             :     QofBook *book;
    1292                 :        1406 :     GncInvoice *invoice = NULL;
    1293                 :             : 
    1294                 :        1406 :     if (!lot) return NULL;
    1295                 :             : 
    1296                 :        1376 :     invoice = gnc_lot_get_cached_invoice (lot);
    1297                 :        1376 :     if (!invoice)
    1298                 :             :     {
    1299                 :         528 :         book = gnc_lot_get_book (lot);
    1300                 :         528 :         qof_instance_get (QOF_INSTANCE(lot), "invoice", &guid, NULL);
    1301                 :         528 :         invoice = gncInvoiceLookup (book, guid);
    1302                 :         528 :         guid_free (guid);
    1303                 :         528 :         gnc_lot_set_cached_invoice (lot, invoice);
    1304                 :             :     }
    1305                 :             : 
    1306                 :        1376 :     return invoice;
    1307                 :             : }
    1308                 :             : 
    1309                 :             : void
    1310                 :          64 : gncInvoiceAttachToTxn (GncInvoice *invoice, Transaction *txn)
    1311                 :             : {
    1312                 :          64 :     if (!invoice || !txn)
    1313                 :           0 :         return;
    1314                 :             : 
    1315                 :          64 :     if (invoice->posted_txn) return;    /* Cannot reset invoice's txn */
    1316                 :             : 
    1317                 :          64 :     xaccTransBeginEdit (txn);
    1318                 :          64 :     qof_instance_set (QOF_INSTANCE (txn), "invoice", //Prop INVOICE
    1319                 :          64 :               qof_instance_get_guid (QOF_INSTANCE (invoice)), NULL);
    1320                 :          64 :     xaccTransSetTxnType (txn, TXN_TYPE_INVOICE);
    1321                 :          64 :     xaccTransCommitEdit (txn);
    1322                 :          64 :     gncInvoiceSetPostedTxn (invoice, txn);
    1323                 :             : }
    1324                 :             : 
    1325                 :             : GncInvoice *
    1326                 :        1978 : gncInvoiceGetInvoiceFromTxn (const Transaction *txn)
    1327                 :             : {
    1328                 :        1978 :     GncGUID *guid = NULL;
    1329                 :             :     QofBook *book;
    1330                 :        1978 :     GncInvoice *invoice = NULL;
    1331                 :             : 
    1332                 :        1978 :     if (!txn) return NULL;
    1333                 :             : 
    1334                 :        1978 :     book = xaccTransGetBook (txn);
    1335                 :        1978 :     qof_instance_get (QOF_INSTANCE (txn), "invoice", &guid, NULL);
    1336                 :        1978 :     invoice = gncInvoiceLookup (book, guid);
    1337                 :        1978 :     guid_free (guid);
    1338                 :        1978 :     return invoice;
    1339                 :             : }
    1340                 :             : 
    1341                 :          27 : gboolean gncInvoiceAmountPositive (const GncInvoice *invoice)
    1342                 :             : {
    1343                 :          27 :     switch (gncInvoiceGetType (invoice))
    1344                 :             :     {
    1345                 :          18 :     case GNC_INVOICE_CUST_INVOICE:
    1346                 :             :     case GNC_INVOICE_VEND_CREDIT_NOTE:
    1347                 :             :     case GNC_INVOICE_EMPL_CREDIT_NOTE:
    1348                 :          18 :         return TRUE;
    1349                 :           9 :     case GNC_INVOICE_CUST_CREDIT_NOTE:
    1350                 :             :     case GNC_INVOICE_VEND_INVOICE:
    1351                 :             :     case GNC_INVOICE_EMPL_INVOICE:
    1352                 :           9 :         return FALSE;
    1353                 :           0 :     case GNC_INVOICE_UNDEFINED:
    1354                 :             :     default:
    1355                 :             :         /* Should never be reached.
    1356                 :             :          * If it is, perhaps a new value is added to GncInvoiceType ? */
    1357                 :           0 :         g_assert_not_reached ();
    1358                 :             :         return FALSE;
    1359                 :             :     }
    1360                 :             : }
    1361                 :             : 
    1362                 :           0 : GHashTable *gncInvoiceGetForeignCurrencies (const GncInvoice *invoice)
    1363                 :             : {
    1364                 :             :     EntryList *entries_iter;
    1365                 :           0 :     gboolean is_cust_doc = (gncInvoiceGetOwnerType (invoice) == GNC_OWNER_CUSTOMER);
    1366                 :           0 :     gboolean is_cn = gncInvoiceGetIsCreditNote (invoice);
    1367                 :           0 :     GHashTable *amt_hash = g_hash_table_new_full (g_direct_hash, g_direct_equal,
    1368                 :             :                                                   NULL, g_free);
    1369                 :           0 :     ENTER ("");
    1370                 :             : 
    1371                 :           0 :     for (entries_iter = invoice->entries; entries_iter != NULL; entries_iter = g_list_next(entries_iter))
    1372                 :             :     {
    1373                 :           0 :         GncEntry *entry = (GncEntry*)entries_iter->data;
    1374                 :             :         Account *this_acc;
    1375                 :             :         gnc_commodity *account_currency;
    1376                 :           0 :         AccountValueList *tt_amts = NULL, *tt_iter;
    1377                 :             : 
    1378                 :             :         /* Check entry's account currency */
    1379                 :           0 :         this_acc = (is_cust_doc ? gncEntryGetInvAccount (entry) :
    1380                 :           0 :                     gncEntryGetBillAccount (entry));
    1381                 :           0 :         account_currency = xaccAccountGetCommodity (this_acc);
    1382                 :             : 
    1383                 :           0 :         if (this_acc &&
    1384                 :           0 :                 !gnc_commodity_equal (gncInvoiceGetCurrency (invoice), account_currency))
    1385                 :             :         {
    1386                 :           0 :             gnc_numeric *curr_amt = (gnc_numeric*) g_hash_table_lookup (amt_hash, account_currency);
    1387                 :           0 :             gnc_numeric *entry_amt = (gnc_numeric*) g_new0 (gnc_numeric, 1);
    1388                 :           0 :             *entry_amt = gncEntryGetDocValue (entry, FALSE, is_cust_doc, is_cn);
    1389                 :           0 :             if (curr_amt)
    1390                 :           0 :                 *entry_amt = gnc_numeric_add (*entry_amt, *curr_amt, GNC_DENOM_AUTO, GNC_HOW_RND_ROUND_HALF_UP);
    1391                 :           0 :             g_hash_table_insert (amt_hash, account_currency, entry_amt);
    1392                 :             :         }
    1393                 :             : 
    1394                 :             :         /* Check currencies of each account in the tax table linked
    1395                 :             :          * to the current entry */
    1396                 :           0 :         tt_amts = gncEntryGetDocTaxValues (entry, is_cust_doc, is_cn);
    1397                 :             : 
    1398                 :           0 :         if (!tt_amts)
    1399                 :           0 :             continue;
    1400                 :             : 
    1401                 :           0 :         for (tt_iter = tt_amts; tt_iter != NULL; tt_iter = g_list_next(tt_iter))
    1402                 :             :         {
    1403                 :           0 :             GncAccountValue *tt_amt_val = (GncAccountValue*)tt_iter->data;
    1404                 :           0 :             Account *tt_acc = tt_amt_val->account;
    1405                 :           0 :             gnc_commodity *tt_acc_currency = xaccAccountGetCommodity (tt_acc);
    1406                 :             : 
    1407                 :           0 :             if (tt_acc &&
    1408                 :           0 :                     !gnc_commodity_equal (gncInvoiceGetCurrency (invoice), tt_acc_currency))
    1409                 :             :             {
    1410                 :           0 :                 gnc_numeric *curr_amt = (gnc_numeric*) g_hash_table_lookup (amt_hash, tt_acc_currency);
    1411                 :           0 :                 gnc_numeric *tt_acc_amt = (gnc_numeric*) g_new0 (gnc_numeric, 1);
    1412                 :           0 :                 *tt_acc_amt = tt_amt_val->value;
    1413                 :           0 :                 if (curr_amt)
    1414                 :           0 :                     *tt_acc_amt = gnc_numeric_add (*tt_acc_amt, *curr_amt, GNC_DENOM_AUTO, GNC_HOW_RND_ROUND_HALF_UP);
    1415                 :           0 :                 g_hash_table_insert (amt_hash, tt_acc_currency, tt_acc_amt);
    1416                 :             :             }
    1417                 :             :         }
    1418                 :           0 :         gncAccountValueDestroy (tt_amts);
    1419                 :             :     }
    1420                 :             : 
    1421                 :           0 :     LEAVE ("");
    1422                 :           0 :     return amt_hash;
    1423                 :             : }
    1424                 :             : 
    1425                 :          66 : static gboolean gncInvoicePostAddSplit (QofBook *book,
    1426                 :             :                                         Account *acc,
    1427                 :             :                                         Transaction *txn,
    1428                 :             :                                         gnc_numeric value,
    1429                 :             :                                         const gchar *memo,
    1430                 :             :                                         const gchar *type,
    1431                 :             :                                         GncInvoice *invoice)
    1432                 :             : {
    1433                 :             :     Split *split;
    1434                 :             : 
    1435                 :          66 :     ENTER ("");
    1436                 :          66 :     split = xaccMallocSplit (book);
    1437                 :             :     /* set action and memo? */
    1438                 :             : 
    1439                 :          66 :     xaccSplitSetMemo (split, memo);
    1440                 :             :     /* set per book option */
    1441                 :          66 :     gnc_set_num_action (NULL, split, gncInvoiceGetID (invoice), type);
    1442                 :             : 
    1443                 :             :     /* Need to insert this split into the account AND txn before
    1444                 :             :      * we set the Base Value.  Otherwise SetBaseValue complains
    1445                 :             :      * that we don't have an account and fails to set the value.
    1446                 :             :      */
    1447                 :          66 :     xaccAccountBeginEdit (acc);
    1448                 :          66 :     xaccAccountInsertSplit (acc, split);
    1449                 :          66 :     xaccAccountCommitEdit (acc);
    1450                 :          66 :     xaccTransAppendSplit (txn, split);
    1451                 :             : 
    1452                 :             :     /* General note on the split creations below:
    1453                 :             :      * Invoice and bill amounts are always stored as positive values in entries
    1454                 :             :      * So to convert them to proper splits, the amounts may have to be reverted
    1455                 :             :      * to have the proper effect on the account balance.
    1456                 :             :      * Credit notes have the opposite effect of invoices/bills, but their amounts
    1457                 :             :      * are stored as negative values as well. So to convert them into splits
    1458                 :             :      * they can be treated exactly the same as their invoice/bill counter parts.
    1459                 :             :      * The net effect is that the owner type is sufficient to determine whether a
    1460                 :             :      * value has to be reverted when converting an invoice/bill/cn amount to a split.
    1461                 :             :      */
    1462                 :          66 :     if (gnc_commodity_equal (xaccAccountGetCommodity (acc), invoice->currency))
    1463                 :             :     {
    1464                 :          66 :         xaccSplitSetBaseValue (split, value,
    1465                 :          66 :                                invoice->currency);
    1466                 :             :     }
    1467                 :             :     else
    1468                 :             :     {
    1469                 :             :         /*need to do conversion */
    1470                 :           0 :         GNCPrice *price = gncInvoiceGetPrice (invoice, xaccAccountGetCommodity (acc));
    1471                 :             : 
    1472                 :           0 :         if (price == NULL)
    1473                 :             :         {
    1474                 :             :             /*This is an error, which shouldn't even be able to happen.
    1475                 :             :               We can't really do anything sensible about it, and this is
    1476                 :             :                         a user-interface free zone so we can't try asking the user
    1477                 :             :               again either, have to return NULL*/
    1478                 :           0 :             PERR("Multiple commodities with no price.");
    1479                 :           0 :             LEAVE ("FALSE");
    1480                 :           0 :             return FALSE;
    1481                 :             :         }
    1482                 :             :         else
    1483                 :             :         {
    1484                 :             :             gnc_numeric converted_amount;
    1485                 :           0 :             xaccSplitSetValue (split, value);
    1486                 :           0 :             converted_amount = gnc_numeric_div (value, gnc_price_get_value (price), GNC_DENOM_AUTO, GNC_HOW_RND_ROUND_HALF_UP);
    1487                 :           0 :             DEBUG("converting from %f to %f\n", gnc_numeric_to_double (value), gnc_numeric_to_double (converted_amount));
    1488                 :           0 :             xaccSplitSetAmount (split, converted_amount);
    1489                 :             :         }
    1490                 :             :     }
    1491                 :             : 
    1492                 :          66 :     LEAVE ("TRUE");
    1493                 :          66 :     return TRUE;
    1494                 :             : }
    1495                 :             : 
    1496                 :          64 : Transaction * gncInvoicePostToAccount (GncInvoice *invoice, Account *acc,
    1497                 :             :                                        time64 post_date, time64 due_date,
    1498                 :             :                                        const char * memo, gboolean accumulatesplits,
    1499                 :             :                                        gboolean autopay)
    1500                 :             : {
    1501                 :             :     Transaction *txn;
    1502                 :             :     QofBook *book;
    1503                 :          64 :     GNCLot *lot = NULL;
    1504                 :             :     GList *iter;
    1505                 :          64 :     GList *splitinfo = NULL;
    1506                 :             :     gnc_numeric total;
    1507                 :             :     gboolean is_cust_doc;
    1508                 :             :     gboolean is_cn;
    1509                 :             :     const char *name, *type;
    1510                 :             :     char *lot_title;
    1511                 :          64 :     Account *ccard_acct = NULL;
    1512                 :             :     const GncOwner *owner;
    1513                 :          64 :     int denom = xaccAccountGetCommoditySCU (acc);
    1514                 :             :     AccountValueList *taxes;
    1515                 :             : 
    1516                 :          64 :     if (!invoice || !acc) return NULL;
    1517                 :          64 :     if (gncInvoiceIsPosted (invoice)) return NULL;
    1518                 :             : 
    1519                 :          64 :     ENTER ("");
    1520                 :          64 :     gncInvoiceBeginEdit (invoice);
    1521                 :          64 :     book = qof_instance_get_book (invoice);
    1522                 :             : 
    1523                 :             :     /* Stabilize the Billing Terms of this invoice */
    1524                 :          64 :     if (invoice->terms)
    1525                 :           4 :         gncInvoiceSetTerms (invoice,
    1526                 :             :                             gncBillTermReturnChild (invoice->terms, TRUE));
    1527                 :             : 
    1528                 :             :     /* GncEntry functions need to know if the invoice/credit note is for a customer or a vendor/employee. */
    1529                 :          64 :     is_cust_doc = (gncInvoiceGetOwnerType (invoice) == GNC_OWNER_CUSTOMER);
    1530                 :          64 :     is_cn = gncInvoiceGetIsCreditNote (invoice);
    1531                 :             : 
    1532                 :             :     /* Figure out if we need to separate out "credit-card" items */
    1533                 :          64 :     owner = gncOwnerGetEndOwner (gncInvoiceGetOwner (invoice));
    1534                 :          64 :     if (gncInvoiceGetOwnerType (invoice) == GNC_OWNER_EMPLOYEE)
    1535                 :           8 :         ccard_acct = gncEmployeeGetCCard (gncOwnerGetEmployee (owner));
    1536                 :             : 
    1537                 :             :     /* Create a new lot for this invoice */
    1538                 :          64 :     lot = gnc_lot_new (book);
    1539                 :          64 :     gncInvoiceAttachToLot (invoice, lot);
    1540                 :          64 :     gnc_lot_begin_edit (lot);
    1541                 :             : 
    1542                 :          64 :     type = gncInvoiceGetTypeString (invoice);
    1543                 :             : 
    1544                 :             :     /* Set the lot title */
    1545                 :          64 :     lot_title = g_strdup_printf ("%s %s", type, gncInvoiceGetID (invoice));
    1546                 :          64 :     gnc_lot_set_title (lot, lot_title);
    1547                 :          64 :     g_free (lot_title);
    1548                 :             : 
    1549                 :             :     /* Create a new transaction */
    1550                 :          64 :     txn = xaccMallocTransaction (book);
    1551                 :          64 :     xaccTransBeginEdit (txn);
    1552                 :             : 
    1553                 :          64 :     name = gncOwnerGetName (gncOwnerGetEndOwner (gncInvoiceGetOwner (invoice)));
    1554                 :             : 
    1555                 :             :     /* Set Transaction Description (Owner Name) , Num (invoice ID or type, based
    1556                 :             :      * on book option), Currency */
    1557                 :          64 :     xaccTransSetDescription (txn, name ? name : "");
    1558                 :          64 :     gnc_set_num_action (txn, NULL, gncInvoiceGetID (invoice), type);
    1559                 :          64 :     xaccTransSetCurrency (txn, invoice->currency);
    1560                 :             : 
    1561                 :             :     /* Entered and Posted at date */
    1562                 :          64 :     xaccTransSetDateEnteredSecs (txn, gnc_time (NULL));
    1563                 :          64 :     xaccTransSetDatePostedSecsNormalized (txn, post_date);
    1564                 :          64 :     gncInvoiceSetDatePosted (invoice, xaccTransRetDatePosted(txn));
    1565                 :             : 
    1566                 :          64 :     xaccTransSetDateDue (txn, due_date);
    1567                 :             : 
    1568                 :             :     /* Get invoice total and taxes. */
    1569                 :          64 :     total = gncInvoiceGetTotal (invoice);
    1570                 :          64 :     taxes = gncInvoiceGetTotalTaxList (invoice);
    1571                 :             :     /* The two functions above return signs relative to the document
    1572                 :             :      * We need to convert them to balance values before we can use them here
    1573                 :             :      * Note the odd construct comparing two booleans is to xor them
    1574                 :             :      * that is, only evaluate true if both are different.
    1575                 :             :      */
    1576                 :          64 :     if (is_cust_doc != is_cn)
    1577                 :             :     {
    1578                 :             :         GList *node;
    1579                 :          50 :         total = gnc_numeric_neg (total);
    1580                 :          54 :         for (node = taxes; node; node = node->next)
    1581                 :             :         {
    1582                 :           4 :             GncAccountValue *acc_val = node->data;
    1583                 :           4 :             acc_val->value = gnc_numeric_neg (acc_val->value);
    1584                 :             :         }
    1585                 :             :     }
    1586                 :             : 
    1587                 :             :     /* Iterate through the entries; sum up everything for each account.
    1588                 :             :      * then create the appropriate splits in this txn.
    1589                 :             :      */
    1590                 :             : 
    1591                 :         155 :     for (iter = gncInvoiceGetEntries (invoice); iter; iter = iter->next)
    1592                 :             :     {
    1593                 :             :         gnc_numeric value, tax;
    1594                 :          91 :         GncEntry * entry = iter->data;
    1595                 :             :         Account *this_acc;
    1596                 :             : 
    1597                 :             :         /* Stabilize the TaxTable in this entry */
    1598                 :          91 :         gncEntryBeginEdit (entry);
    1599                 :          91 :         if (is_cust_doc)
    1600                 :          75 :             gncEntrySetInvTaxTable
    1601                 :             :             (entry, gncTaxTableReturnChild (gncEntryGetInvTaxTable (entry), TRUE));
    1602                 :             :         else
    1603                 :             :         {
    1604                 :          16 :             gncEntrySetBillTaxTable
    1605                 :             :             (entry, gncTaxTableReturnChild (gncEntryGetBillTaxTable (entry), TRUE));
    1606                 :             : 
    1607                 :             :             /* If this is a bill, and the entry came from an invoice originally, copy the price */
    1608                 :          16 :             if (gncEntryGetBillable (entry))
    1609                 :             :             {
    1610                 :             :                 /* We need to set the net price since it may be another tax rate for invoices than bills */
    1611                 :           0 :                 gncEntrySetInvPrice (entry, gncEntryGetPrice (entry, FALSE, TRUE));
    1612                 :           0 :                 gncEntrySetInvTaxIncluded (entry, FALSE);
    1613                 :             :             }
    1614                 :             :         }
    1615                 :          91 :         gncEntryCommitEdit (entry);
    1616                 :             : 
    1617                 :             :         /* Obtain the Entry's Value and TaxValues
    1618                 :             :            Note we use rounded values here and below to prevent creating an imbalanced transaction */
    1619                 :          91 :         value = gncEntryGetBalValue (entry, TRUE, is_cust_doc);
    1620                 :          91 :         tax   = gncEntryGetBalTaxValue (entry, TRUE, is_cust_doc);
    1621                 :             : 
    1622                 :          91 :         DEBUG ("Tax %" PRId64 "/%" PRId64 " on entry value %" PRId64 "/%" PRId64,
    1623                 :             :                tax.num, tax.denom, value.num, value.denom);
    1624                 :             :         /* add the value for the account split */
    1625                 :          91 :         this_acc = (is_cust_doc ? gncEntryGetInvAccount (entry) :
    1626                 :          16 :                     gncEntryGetBillAccount (entry));
    1627                 :          91 :         if (this_acc)
    1628                 :             :         {
    1629                 :          90 :             if (gnc_numeric_check (value) == GNC_ERROR_OK)
    1630                 :             :             {
    1631                 :          90 :                 if (accumulatesplits)
    1632                 :          90 :                     splitinfo = gncAccountValueAdd (splitinfo, this_acc, value);
    1633                 :             :                     /* Adding to total in case of accumulatesplits will be deferred to later when each split is effectively added */
    1634                 :           0 :                 else if (!gncInvoicePostAddSplit (book, this_acc, txn, value,
    1635                 :           0 :                                                   gncEntryGetDescription (entry),
    1636                 :             :                                                   type, invoice))
    1637                 :             :                 {
    1638                 :             :                     /*This is an error, which shouldn't even be able to happen.
    1639                 :             :                       We can't really do anything sensible about it, and this is
    1640                 :             :                       a user-interface free zone so we can't try asking the user
    1641                 :             :                       again either, have to return NULL*/
    1642                 :           0 :                     PERR("Failed to add split %s", gncEntryGetDescription (entry));
    1643                 :           0 :                     LEAVE ("NULL");
    1644                 :           0 :                     return NULL;
    1645                 :             :                 }
    1646                 :             : 
    1647                 :             :                 /* If there is a credit-card account, and this is a CCard
    1648                 :             :                  * payment type, subtract it from the total, and instead
    1649                 :             :                  * create a split to the CC Acct with a memo of the entry
    1650                 :             :                  * description instead of the provided memo.  Note that the
    1651                 :             :                  * value reversal is the same as the post account.
    1652                 :             :                  *
    1653                 :             :                  * Note: we don't have to worry about the tax values --
    1654                 :             :                  * expense vouchers don't have them.
    1655                 :             :                  */
    1656                 :          90 :                 if (ccard_acct && gncEntryGetBillPayment (entry) == GNC_PAYMENT_CARD)
    1657                 :             :                 {
    1658                 :             :                     Split *split;
    1659                 :             : 
    1660                 :           0 :                     total = gnc_numeric_sub (total, value, denom,
    1661                 :             :                                              GNC_HOW_DENOM_EXACT | GNC_HOW_RND_ROUND_HALF_UP);
    1662                 :             : 
    1663                 :           0 :                     split = xaccMallocSplit (book);
    1664                 :           0 :                     xaccSplitSetMemo (split, gncEntryGetDescription (entry));
    1665                 :             :                     /* set action based on book option */
    1666                 :           0 :                     gnc_set_num_action (NULL, split, gncInvoiceGetID (invoice), type);
    1667                 :           0 :                     xaccAccountBeginEdit (ccard_acct);
    1668                 :           0 :                     xaccAccountInsertSplit (ccard_acct, split);
    1669                 :           0 :                     xaccAccountCommitEdit (ccard_acct);
    1670                 :           0 :                     xaccTransAppendSplit (txn, split);
    1671                 :           0 :                     xaccSplitSetBaseValue (split, gnc_numeric_neg (value),
    1672                 :           0 :                                            invoice->currency);
    1673                 :             : 
    1674                 :             :                 }
    1675                 :             : 
    1676                 :             :             }
    1677                 :             :             else
    1678                 :           0 :                 PWARN ("bad value in our entry");
    1679                 :             :         }
    1680                 :             : 
    1681                 :             :         /* check the taxes */
    1682                 :          91 :         if (gnc_numeric_check (tax) != GNC_ERROR_OK)
    1683                 :           0 :             PWARN ("bad tax in our entry");
    1684                 :             : 
    1685                 :             :     } /* for */
    1686                 :             : 
    1687                 :             : 
    1688                 :             :     /* now merge in the TaxValues */
    1689                 :          64 :     splitinfo = gncAccountValueAddList (splitinfo, taxes);
    1690                 :          64 :     gncAccountValueDestroy (taxes);
    1691                 :             : 
    1692                 :             :     /* Iterate through the splitinfo list and generate the splits */
    1693                 :          64 :     if (splitinfo)
    1694                 :          62 :         PINFO ("Processing Split List");
    1695                 :         130 :     for (iter = splitinfo; iter; iter = iter->next)
    1696                 :             :     {
    1697                 :          66 :         GncAccountValue *acc_val = iter->data;
    1698                 :             : 
    1699                 :             :         //gnc_numeric amt_rounded = gnc_numeric_convert(acc_val->value,
    1700                 :             :         //    denom, GNC_HOW_DENOM_EXACT | GNC_HOW_RND_ROUND_HALF_UP);
    1701                 :          66 :         if (!gncInvoicePostAddSplit (book, acc_val->account, txn, acc_val->value,
    1702                 :             :                                      memo, type, invoice))
    1703                 :             :         {
    1704                 :             :             /*This is an error, which shouldn't even be able to happen.
    1705                 :             :               We can't really do anything sensible about it, and this is
    1706                 :             :               a user-interface free zone so we can't try asking the user
    1707                 :             :               again either, have to return NULL*/
    1708                 :           0 :             PERR("Failed to add split %s, aborting accumulated splits.", memo);
    1709                 :           0 :             return NULL;
    1710                 :             :         }
    1711                 :             :     }
    1712                 :             : 
    1713                 :             :     /* If there is a ccard account, we may have an additional "to_card" payment.
    1714                 :             :      * we should make that now.
    1715                 :             :      */
    1716                 :          64 :     if (ccard_acct && !gnc_numeric_zero_p (invoice->to_charge_amount))
    1717                 :             :     {
    1718                 :           0 :         Split *split = xaccMallocSplit (book);
    1719                 :             : 
    1720                 :             :         /* To charge amount is stored in document value. We need balance value here
    1721                 :             :          * so convert if necessary. */
    1722                 :           0 :         gnc_numeric to_charge_bal_amount = (is_cn ? gnc_numeric_neg (invoice->to_charge_amount)
    1723                 :           0 :                                             : invoice->to_charge_amount);
    1724                 :             : 
    1725                 :           0 :         PINFO ("Process to_card payment split");
    1726                 :             :         /* Set memo. */
    1727                 :           0 :         xaccSplitSetMemo (split, _("Extra to Charge Card"));
    1728                 :             :         /* Set action based on book option */
    1729                 :           0 :         gnc_set_num_action (NULL, split, gncInvoiceGetID (invoice), type);
    1730                 :             : 
    1731                 :           0 :         xaccAccountBeginEdit (ccard_acct);
    1732                 :           0 :         xaccAccountInsertSplit (ccard_acct, split);
    1733                 :           0 :         xaccAccountCommitEdit (ccard_acct);
    1734                 :           0 :         xaccTransAppendSplit (txn, split);
    1735                 :           0 :         xaccSplitSetBaseValue (split, gnc_numeric_neg (to_charge_bal_amount),
    1736                 :           0 :                                invoice->currency);
    1737                 :             : 
    1738                 :           0 :         total = gnc_numeric_sub (total, to_charge_bal_amount, denom,
    1739                 :             :                                  GNC_HOW_DENOM_EXACT | GNC_HOW_RND_ROUND_HALF_UP);
    1740                 :             :     }
    1741                 :             : 
    1742                 :             :     /* Now create the Posted split (which is the opposite sign of the above splits) */
    1743                 :             :     {
    1744                 :          64 :         Split *split = xaccMallocSplit (book);
    1745                 :             : 
    1746                 :          64 :         PINFO ("Process to_card balancing split");
    1747                 :             :         /* Set memo */
    1748                 :          64 :         xaccSplitSetMemo (split, memo);
    1749                 :             :         /* Set action based on book option */
    1750                 :          64 :         gnc_set_num_action (NULL, split, gncInvoiceGetID (invoice), type);
    1751                 :             : 
    1752                 :          64 :         xaccAccountBeginEdit (acc);
    1753                 :          64 :         xaccAccountInsertSplit (acc, split);
    1754                 :          64 :         xaccAccountCommitEdit (acc);
    1755                 :          64 :         xaccTransAppendSplit (txn, split);
    1756                 :          64 :         xaccSplitSetBaseValue (split, gnc_numeric_neg (total),
    1757                 :          64 :                                invoice->currency);
    1758                 :             : 
    1759                 :             :         /* add this split to the lot */
    1760                 :          64 :         gnc_lot_add_split (lot, split);
    1761                 :             :     }
    1762                 :             : 
    1763                 :             :     /* Now attach this invoice to the txn and account */
    1764                 :          64 :     gncInvoiceAttachToTxn (invoice, txn);
    1765                 :          64 :     gncInvoiceSetPostedAcc (invoice, acc);
    1766                 :             : 
    1767                 :          64 :     xaccTransSetReadOnly (txn, _("Generated from an invoice. Try unposting the invoice."));
    1768                 :          64 :     xaccTransCommitEdit (txn);
    1769                 :             : 
    1770                 :          64 :     gncAccountValueDestroy (splitinfo);
    1771                 :             : 
    1772                 :          64 :     gnc_lot_commit_edit (lot);
    1773                 :             :     /* Not strictly necessary, since it was done by the Set calls
    1774                 :             :      * above, but good insurance. */
    1775                 :          64 :     DEBUG("Committing Invoice %s", invoice->id);
    1776                 :          64 :     mark_invoice (invoice);
    1777                 :          64 :     gncInvoiceCommitEdit (invoice);
    1778                 :             : 
    1779                 :             :     /* If requested, attempt to automatically apply open payments
    1780                 :             :      * and reverse documents to this lot to close it (or at least
    1781                 :             :      * reduce its balance) */
    1782                 :          64 :     if (autopay)
    1783                 :           0 :         gncInvoiceAutoApplyPayments (invoice);
    1784                 :             : 
    1785                 :          64 :     LEAVE ("");
    1786                 :          64 :     return txn;
    1787                 :             : }
    1788                 :             : 
    1789                 :             : gboolean
    1790                 :           8 : gncInvoiceUnpost (GncInvoice *invoice, gboolean reset_tax_tables)
    1791                 :             : {
    1792                 :             :     Transaction *txn;
    1793                 :             :     GNCLot *lot;
    1794                 :             :     GList *lot_split_list, *lot_split_iter;
    1795                 :             : 
    1796                 :           8 :     if (!invoice) return FALSE;
    1797                 :           8 :     if (!gncInvoiceIsPosted (invoice)) return FALSE;
    1798                 :             : 
    1799                 :           8 :     txn = gncInvoiceGetPostedTxn (invoice);
    1800                 :           8 :     g_return_val_if_fail (txn, FALSE);
    1801                 :             : 
    1802                 :           8 :     lot = gncInvoiceGetPostedLot (invoice);
    1803                 :           8 :     g_return_val_if_fail (lot, FALSE);
    1804                 :             : 
    1805                 :           8 :     ENTER ("");
    1806                 :             :     /* Destroy the Posted Transaction */
    1807                 :           8 :     xaccTransClearReadOnly (txn);
    1808                 :           8 :     xaccTransBeginEdit (txn);
    1809                 :           8 :     xaccTransDestroy (txn);
    1810                 :           8 :     xaccTransCommitEdit (txn);
    1811                 :             : 
    1812                 :             :     /* Disconnect the lot from the invoice; re-attach to the invoice owner */
    1813                 :           8 :     gncInvoiceDetachFromLot (lot);
    1814                 :           8 :     gncOwnerAttachToLot (&invoice->owner, lot);
    1815                 :             : 
    1816                 :             :     /* Check if this invoice was linked to other lots (payments/inverse signed
    1817                 :             :      * invoices).
    1818                 :             :      * If this is the case, recreate the link transaction between all the remaining lots.
    1819                 :             :      *
    1820                 :             :      * Note that before GnuCash 2.6 payments were not stored in separate lots, but
    1821                 :             :      * always ended up in invoice lots when matched to an invoice. Over-payments
    1822                 :             :      * were copied to a new lot, to which later an invoice was added again and so on.
    1823                 :             :      * These over-payments were handled with automatic payment forward transactions.
    1824                 :             :      * You could consider these transactions to be links between lots as well, but
    1825                 :             :      * to avoid some unexpected behavior, these will not be altered here.
    1826                 :             :      */
    1827                 :             : 
    1828                 :             :     // Note: make a copy of the lot list here, when splits are deleted from the lot,
    1829                 :             :     //       the original list may be destroyed by the lot code.
    1830                 :           8 :     lot_split_list = g_list_copy (gnc_lot_get_split_list (lot));
    1831                 :           8 :     if (lot_split_list)
    1832                 :           0 :         PINFO ("Recreating link transactions for remaining lots");
    1833                 :           8 :     for (lot_split_iter = lot_split_list; lot_split_iter; lot_split_iter = lot_split_iter->next)
    1834                 :             :     {
    1835                 :           0 :         Split *split = lot_split_iter->data;
    1836                 :             :         GList *other_split_list, *list_iter;
    1837                 :           0 :         Transaction *other_txn = xaccSplitGetParent (split);
    1838                 :           0 :         GList *lot_list = NULL;
    1839                 :             : 
    1840                 :             :         /* Only work with transactions that link invoices and payments.
    1841                 :             :          * Note: this check also catches the possible case of NULL splits. */
    1842                 :           0 :         if (xaccTransGetTxnType (other_txn) != TXN_TYPE_LINK)
    1843                 :           0 :             continue;
    1844                 :             : 
    1845                 :             :         /* Save a list of lots this linking transaction linked to */
    1846                 :           0 :         other_split_list = xaccTransGetSplitList (other_txn);
    1847                 :           0 :         for (list_iter = other_split_list; list_iter; list_iter = list_iter->next)
    1848                 :             :         {
    1849                 :           0 :             Split *other_split = list_iter->data;
    1850                 :           0 :             GNCLot *other_lot = xaccSplitGetLot (other_split);
    1851                 :             : 
    1852                 :             :             /* Omit the lot we are about to delete */
    1853                 :           0 :             if (other_lot == lot)
    1854                 :           0 :                 continue;
    1855                 :             : 
    1856                 :           0 :             lot_list = g_list_prepend (lot_list, other_lot);
    1857                 :             :         }
    1858                 :             :         /* Maintain original split order */
    1859                 :           0 :         lot_list = g_list_reverse (lot_list);
    1860                 :             : 
    1861                 :             :         /* Now remove this link transaction. */
    1862                 :           0 :         xaccTransClearReadOnly (other_txn);
    1863                 :           0 :         xaccTransBeginEdit (other_txn);
    1864                 :           0 :         xaccTransDestroy (other_txn);
    1865                 :           0 :         xaccTransCommitEdit (other_txn);
    1866                 :             : 
    1867                 :             :         /* Re-balance the saved lots as well as is possible */
    1868                 :           0 :         gncOwnerAutoApplyPaymentsWithLots (&invoice->owner, lot_list);
    1869                 :             : 
    1870                 :             :         /* If any of the saved lots has no more splits, then destroy it.
    1871                 :             :          * Otherwise if any has an invoice associated with it,
    1872                 :             :          * send it a modified event to reset its paid status */
    1873                 :           0 :         for (list_iter = lot_list; list_iter; list_iter = list_iter->next)
    1874                 :             :         {
    1875                 :           0 :             GNCLot *other_lot = list_iter->data;
    1876                 :           0 :             GncInvoice *other_invoice = gncInvoiceGetInvoiceFromLot (other_lot);
    1877                 :             : 
    1878                 :           0 :             if (!gnc_lot_count_splits (other_lot))
    1879                 :           0 :                 gnc_lot_destroy (other_lot);
    1880                 :           0 :             else if (other_invoice)
    1881                 :           0 :                 qof_event_gen (QOF_INSTANCE(other_invoice), QOF_EVENT_MODIFY, NULL);
    1882                 :             :         }
    1883                 :           0 :         g_list_free (lot_list);
    1884                 :             :     }
    1885                 :           8 :     g_list_free (lot_split_list);
    1886                 :             : 
    1887                 :             :     /* If the lot has no splits, then destroy it */
    1888                 :           8 :     if (!gnc_lot_count_splits (lot))
    1889                 :           8 :         gnc_lot_destroy (lot);
    1890                 :             : 
    1891                 :             :     /* Clear out the invoice posted information */
    1892                 :           8 :     gncInvoiceBeginEdit (invoice);
    1893                 :             : 
    1894                 :           8 :     invoice->posted_acc = NULL;
    1895                 :           8 :     invoice->posted_txn = NULL;
    1896                 :           8 :     invoice->posted_lot = NULL;
    1897                 :           8 :     invoice->date_posted = INT64_MAX;
    1898                 :             : 
    1899                 :             :     /* if we've been asked to reset the tax tables, then do so */
    1900                 :           8 :     if (reset_tax_tables)
    1901                 :             :     {
    1902                 :           8 :         gboolean is_cust_doc = (gncInvoiceGetOwnerType (invoice) == GNC_OWNER_CUSTOMER);
    1903                 :             :         GList *iter;
    1904                 :             : 
    1905                 :          15 :         for (iter = gncInvoiceGetEntries (invoice); iter; iter = iter->next)
    1906                 :             :         {
    1907                 :           7 :             GncEntry *entry = iter->data;
    1908                 :             : 
    1909                 :           7 :             gncEntryBeginEdit (entry);
    1910                 :           7 :             if (is_cust_doc)
    1911                 :           7 :                 gncEntrySetInvTaxTable (entry,
    1912                 :           7 :                                         gncTaxTableGetParent (gncEntryGetInvTaxTable( entry)));
    1913                 :             :             else
    1914                 :           0 :                 gncEntrySetBillTaxTable (entry,
    1915                 :           0 :                                          gncTaxTableGetParent (gncEntryGetBillTaxTable (entry)));
    1916                 :           7 :             gncEntryCommitEdit (entry);
    1917                 :             :         }
    1918                 :             :     }
    1919                 :             : 
    1920                 :           8 :     mark_invoice (invoice);
    1921                 :           8 :     gncInvoiceCommitEdit (invoice);
    1922                 :             : 
    1923                 :           8 :     LEAVE ("TRUE");
    1924                 :             : 
    1925                 :           8 :     return TRUE;
    1926                 :             : }
    1927                 :             : 
    1928                 :             : struct lotmatch
    1929                 :             : {
    1930                 :             :     const GncOwner *owner;
    1931                 :             :     gboolean positive_balance;
    1932                 :             : };
    1933                 :             : 
    1934                 :             : static gboolean
    1935                 :           0 : gnc_lot_match_owner_balancing (GNCLot *lot, gpointer user_data)
    1936                 :             : {
    1937                 :           0 :     struct lotmatch *lm = user_data;
    1938                 :             :     GncOwner owner_def;
    1939                 :             :     const GncOwner *owner;
    1940                 :           0 :     gnc_numeric balance = gnc_lot_get_balance (lot);
    1941                 :             : 
    1942                 :             :     /* Could (part of) this lot serve to balance the lot
    1943                 :             :      * for which this query was run ?*/
    1944                 :           0 :     if (lm->positive_balance == gnc_numeric_positive_p (balance))
    1945                 :           0 :         return FALSE;
    1946                 :             : 
    1947                 :             :     /* Is it ours? Either the lot owner or the lot invoice owner should match */
    1948                 :           0 :     if (!gncOwnerGetOwnerFromLot (lot, &owner_def))
    1949                 :             :     {
    1950                 :           0 :         const GncInvoice *invoice = gncInvoiceGetInvoiceFromLot (lot);
    1951                 :           0 :         if (!invoice)
    1952                 :           0 :             return FALSE;
    1953                 :           0 :         owner = gncOwnerGetEndOwner (gncInvoiceGetOwner (invoice));
    1954                 :             :     }
    1955                 :             :     else
    1956                 :           0 :         owner = gncOwnerGetEndOwner (&owner_def);
    1957                 :             : 
    1958                 :           0 :     return gncOwnerEqual (owner, lm->owner);
    1959                 :             : }
    1960                 :             : 
    1961                 :           1 : void gncInvoiceAutoApplyPayments (GncInvoice *invoice)
    1962                 :             : {
    1963                 :             :     GNCLot *inv_lot;
    1964                 :             :     Account *acct;
    1965                 :             :     const GncOwner *owner;
    1966                 :             :     GList *lot_list;
    1967                 :             :     struct lotmatch lm;
    1968                 :             : 
    1969                 :             :     /* General note: "paying" in this context means balancing
    1970                 :             :      * a lot, by linking opposite signed lots together. So below the term
    1971                 :             :      * "payment" can both mean a true payment or it can mean a document of
    1972                 :             :      * the opposite sign (invoice vs credit note). It just
    1973                 :             :      * depends on what type of document was given as parameter
    1974                 :             :      * to this function. */
    1975                 :             : 
    1976                 :             :     /* Payments can only be applied to posted invoices */
    1977                 :           1 :     g_return_if_fail (invoice);
    1978                 :           1 :     g_return_if_fail (invoice->posted_lot);
    1979                 :             : 
    1980                 :           1 :     inv_lot = invoice->posted_lot;
    1981                 :           1 :     acct = invoice->posted_acc;
    1982                 :           1 :     owner = gncOwnerGetEndOwner (gncInvoiceGetOwner (invoice));
    1983                 :             : 
    1984                 :             :     /* Find all lots whose balance (or part of their balance) could be
    1985                 :             :      * used to close this lot.
    1986                 :             :      * To be eligible, the lots have to have an opposite signed balance
    1987                 :             :      * and be for the same owner.
    1988                 :             :      * For example, for an invoice lot, payment lots and credit note lots
    1989                 :             :      * could be used. */
    1990                 :           1 :     lm.positive_balance =  gnc_numeric_positive_p (gnc_lot_get_balance (inv_lot));
    1991                 :           1 :     lm.owner = owner;
    1992                 :           1 :     lot_list = xaccAccountFindOpenLots (acct, gnc_lot_match_owner_balancing,
    1993                 :             :                                         &lm, NULL);
    1994                 :             : 
    1995                 :           1 :     lot_list = g_list_prepend (lot_list, inv_lot);
    1996                 :           1 :     gncOwnerAutoApplyPaymentsWithLots (owner, lot_list);
    1997                 :           1 :     g_list_free (lot_list);
    1998                 :             : }
    1999                 :             : 
    2000                 :             : /*
    2001                 :             :  * Create a payment of "amount" for the invoice owner and attempt
    2002                 :             :  * to balance it with the given invoice.
    2003                 :             :  */
    2004                 :             : void
    2005                 :          12 : gncInvoiceApplyPayment (const GncInvoice *invoice, Transaction *txn,
    2006                 :             :                         Account *xfer_acc, gnc_numeric amount,
    2007                 :             :                         gnc_numeric exch, time64 date,
    2008                 :             :                         const char *memo, const char *num)
    2009                 :             : {
    2010                 :             :     GNCLot *payment_lot;
    2011                 :          12 :     GList *selected_lots = NULL;
    2012                 :             :     const GncOwner *owner;
    2013                 :             : 
    2014                 :             :     /* Verify our arguments */
    2015                 :          12 :     if (!invoice || !gncInvoiceIsPosted (invoice) || !xfer_acc) return;
    2016                 :             : 
    2017                 :          12 :     owner = gncOwnerGetEndOwner (gncInvoiceGetOwner (invoice));
    2018                 :          12 :     g_return_if_fail (owner->owner.undefined);
    2019                 :             : 
    2020                 :             :     /* Create a lot for this payment */
    2021                 :          12 :     payment_lot = gncOwnerCreatePaymentLotSecs (owner, &txn,
    2022                 :          12 :                                                 invoice->posted_acc,
    2023                 :             :                                                 xfer_acc, amount, exch,
    2024                 :             :                                                 date, memo, num);
    2025                 :             : 
    2026                 :             :     /* Select the invoice as only payment candidate */
    2027                 :          12 :     selected_lots = g_list_prepend (selected_lots, invoice->posted_lot);
    2028                 :             : 
    2029                 :             :     /* And link the invoice lot and the payment lot together as well as possible. */
    2030                 :          12 :     if (payment_lot)
    2031                 :          12 :         selected_lots = g_list_prepend (selected_lots, payment_lot);
    2032                 :          12 :     gncOwnerAutoApplyPaymentsWithLots (owner, selected_lots);
    2033                 :             : }
    2034                 :             : 
    2035                 :         115 : gboolean gncInvoiceIsPosted (const GncInvoice *invoice)
    2036                 :             : {
    2037                 :         115 :     if (!invoice) return FALSE;
    2038                 :         115 :     return GNC_IS_TRANSACTION(gncInvoiceGetPostedTxn (invoice));
    2039                 :             : }
    2040                 :             : 
    2041                 :          15 : gboolean gncInvoiceIsPaid (const GncInvoice *invoice)
    2042                 :             : {
    2043                 :          15 :     if (!invoice) return FALSE;
    2044                 :          15 :     if (!invoice->posted_lot) return FALSE;
    2045                 :          15 :     return gnc_lot_is_closed (invoice->posted_lot);
    2046                 :             : }
    2047                 :             : 
    2048                 :             : /* ================================================================== */
    2049                 :             : 
    2050                 :         681 : void gncInvoiceBeginEdit (GncInvoice *invoice)
    2051                 :             : {
    2052                 :         681 :     qof_begin_edit (&invoice->inst);
    2053                 :         681 : }
    2054                 :             : 
    2055                 :           0 : static void gncInvoiceOnError (QofInstance *inst, QofBackendError errcode)
    2056                 :             : {
    2057                 :           0 :     PERR("Invoice QofBackend Failure: %d", errcode);
    2058                 :           0 :     gnc_engine_signal_commit_error (errcode);
    2059                 :           0 : }
    2060                 :             : 
    2061                 :         350 : static void gncInvoiceOnDone (QofInstance *invoice) { }
    2062                 :             : 
    2063                 :          26 : static void invoice_free (QofInstance *inst)
    2064                 :             : {
    2065                 :          26 :     GncInvoice *invoice = (GncInvoice *) inst;
    2066                 :          26 :     gncInvoiceFree (invoice);
    2067                 :          26 : }
    2068                 :             : 
    2069                 :         681 : void gncInvoiceCommitEdit (GncInvoice *invoice)
    2070                 :             : {
    2071                 :         681 :     if (!qof_commit_edit (QOF_INSTANCE(invoice))) return;
    2072                 :         376 :     qof_commit_edit_part2 (&invoice->inst, gncInvoiceOnError,
    2073                 :             :                            gncInvoiceOnDone, invoice_free);
    2074                 :             : }
    2075                 :             : 
    2076                 :           0 : int gncInvoiceCompare (const GncInvoice *a, const GncInvoice *b)
    2077                 :             : {
    2078                 :             :     int compare;
    2079                 :             : 
    2080                 :           0 :     if (a == b) return 0;
    2081                 :           0 :     if (!a) return -1;
    2082                 :           0 :     if (!b) return 1;
    2083                 :             : 
    2084                 :           0 :     compare = g_strcmp0 (a->id, b->id);
    2085                 :           0 :     if (compare) return compare;
    2086                 :           0 :     if (a->date_opened != b->date_opened) return a->date_opened - b->date_opened;
    2087                 :           0 :     if (a->date_posted != b->date_posted) return a->date_posted - b->date_posted;
    2088                 :           0 :     return qof_instance_guid_compare(a, b);
    2089                 :             : }
    2090                 :             : 
    2091                 :           0 : gboolean gncInvoiceEqual(const GncInvoice *a, const GncInvoice *b)
    2092                 :             : {
    2093                 :           0 :     if (a == NULL && b == NULL) return TRUE;
    2094                 :           0 :     if (a == NULL || b == NULL) return FALSE;
    2095                 :             : 
    2096                 :           0 :     g_return_val_if_fail (GNC_IS_INVOICE(a), FALSE);
    2097                 :           0 :     g_return_val_if_fail (GNC_IS_INVOICE(b), FALSE);
    2098                 :             : 
    2099                 :           0 :     if (g_strcmp0 (a->id, b->id) != 0)
    2100                 :             :     {
    2101                 :           0 :         PWARN("IDs differ: %s vs %s", a->id, b->id);
    2102                 :           0 :         return FALSE;
    2103                 :             :     }
    2104                 :             : 
    2105                 :           0 :     if (g_strcmp0 (a->notes, b->notes) != 0)
    2106                 :             :     {
    2107                 :           0 :         PWARN("Notes differ: %s vs %s", a->notes, b->notes);
    2108                 :           0 :         return FALSE;
    2109                 :             :     }
    2110                 :             : 
    2111                 :           0 :     if (g_strcmp0 (a->billing_id, b->billing_id) != 0)
    2112                 :             :     {
    2113                 :           0 :         PWARN("Billing IDs differ: %s vs %s", a->billing_id, b->billing_id);
    2114                 :           0 :         return FALSE;
    2115                 :             :     }
    2116                 :             : 
    2117                 :           0 :     if (g_strcmp0 (a->printname, b->printname) != 0)
    2118                 :             :     {
    2119                 :           0 :         PWARN("Printnames differ: %s vs %s", a->printname, b->printname);
    2120                 :           0 :         return FALSE;
    2121                 :             :     }
    2122                 :             : 
    2123                 :           0 :     if (a->active != b->active)
    2124                 :             :     {
    2125                 :           0 :         PWARN("Active flags differ");
    2126                 :           0 :         return FALSE;
    2127                 :             :     }
    2128                 :             : 
    2129                 :           0 :     if (!gncBillTermEqual (a->terms, b->terms))
    2130                 :             :     {
    2131                 :           0 :         PWARN("Billterms differ");
    2132                 :           0 :         return FALSE;
    2133                 :             :     }
    2134                 :             : 
    2135                 :           0 :     if (!gncJobEqual (a->job, b->job))
    2136                 :             :     {
    2137                 :           0 :         PWARN("Jobs differ");
    2138                 :           0 :         return FALSE;
    2139                 :             :     }
    2140                 :             : 
    2141                 :           0 :     if (!gnc_commodity_equal (a->currency, b->currency))
    2142                 :             :     {
    2143                 :           0 :         PWARN("Currencies differ");
    2144                 :           0 :         return FALSE;
    2145                 :             :     }
    2146                 :             : 
    2147                 :           0 :     if (!xaccAccountEqual (a->posted_acc, b->posted_acc, TRUE))
    2148                 :             :     {
    2149                 :           0 :         PWARN("Posted accounts differ");
    2150                 :           0 :         return FALSE;
    2151                 :             :     }
    2152                 :             : 
    2153                 :           0 :     if (!xaccTransEqual (a->posted_txn, b->posted_txn, TRUE, TRUE, TRUE, FALSE))
    2154                 :             :     {
    2155                 :           0 :         PWARN("Posted tx differ");
    2156                 :           0 :         return FALSE;
    2157                 :             :     }
    2158                 :             : 
    2159                 :             : #if 0
    2160                 :             :     if (!gncLotEqual (a->posted_lot, b->posted_lot))
    2161                 :             :     {
    2162                 :             :         PWARN("Posted lots differ");
    2163                 :             :         return FALSE;
    2164                 :             :     }
    2165                 :             : #endif
    2166                 :             : 
    2167                 :             :     /* FIXME: Need real checks */
    2168                 :             : #if 0
    2169                 :             :     GList       *entries;
    2170                 :             :     GList       *prices;
    2171                 :             :     GncOwner    owner;
    2172                 :             :     GncOwner    billto;
    2173                 :             :     time64      date_opened;
    2174                 :             :     time64      date_posted;
    2175                 :             : 
    2176                 :             :     gnc_numeric to_charge_amount;
    2177                 :             : #endif
    2178                 :             : 
    2179                 :           0 :     return TRUE;
    2180                 :             : }
    2181                 :             : 
    2182                 :             : /* ============================================================= */
    2183                 :             : /* Package-Private functions */
    2184                 :             : 
    2185                 :           0 : static const char * _gncInvoicePrintable (gpointer obj)
    2186                 :             : {
    2187                 :           0 :     GncInvoice *invoice = obj;
    2188                 :             : 
    2189                 :           0 :     g_return_val_if_fail (invoice, NULL);
    2190                 :             : 
    2191                 :           0 :     if (qof_instance_get_dirty_flag (invoice) || invoice->printname == NULL)
    2192                 :             :     {
    2193                 :           0 :         if (invoice->printname) g_free (invoice->printname);
    2194                 :             : 
    2195                 :           0 :         invoice->printname =
    2196                 :           0 :             g_strdup_printf ("%s%s", invoice->id,
    2197                 :           0 :                              gncInvoiceIsPosted (invoice) ? _(" (posted)") : "");
    2198                 :             :     }
    2199                 :             : 
    2200                 :           0 :     return invoice->printname;
    2201                 :             : }
    2202                 :             : 
    2203                 :             : static void
    2204                 :          13 : destroy_invoice_on_book_close (QofInstance *ent, gpointer data)
    2205                 :             : {
    2206                 :          13 :     GncInvoice* invoice = GNC_INVOICE(ent);
    2207                 :             : 
    2208                 :          13 :     gncInvoiceBeginEdit (invoice);
    2209                 :          13 :     gncInvoiceDestroy (invoice);
    2210                 :          13 : }
    2211                 :             : 
    2212                 :             : static void
    2213                 :         156 : gnc_invoice_book_end (QofBook* book)
    2214                 :             : {
    2215                 :             :     QofCollection *col;
    2216                 :             : 
    2217                 :         156 :     col = qof_book_get_collection (book, GNC_ID_INVOICE);
    2218                 :         156 :     qof_collection_foreach (col, destroy_invoice_on_book_close, NULL);
    2219                 :         156 : }
    2220                 :             : 
    2221                 :             : static QofObject gncInvoiceDesc =
    2222                 :             : {
    2223                 :             :     DI(.interface_version = ) QOF_OBJECT_VERSION,
    2224                 :             :     DI(.e_type            = ) _GNC_MOD_NAME,
    2225                 :             :     DI(.type_label        = ) "Invoice",
    2226                 :             :     DI(.create            = ) (gpointer)gncInvoiceCreate,
    2227                 :             :     DI(.book_begin        = ) NULL,
    2228                 :             :     DI(.book_end          = ) gnc_invoice_book_end,
    2229                 :             :     DI(.is_dirty          = ) qof_collection_is_dirty,
    2230                 :             :     DI(.mark_clean        = ) qof_collection_mark_clean,
    2231                 :             :     DI(.foreach           = ) qof_collection_foreach,
    2232                 :             :     DI(.printable         = ) _gncInvoicePrintable,
    2233                 :             :     DI(.version_cmp       = ) (int (*)(gpointer, gpointer)) qof_instance_version_cmp,
    2234                 :             : };
    2235                 :             : 
    2236                 :             : static void
    2237                 :          84 : reg_lot (void)
    2238                 :             : {
    2239                 :             :     static QofParam params[] =
    2240                 :             :     {
    2241                 :             :         {
    2242                 :             :             INVOICE_FROM_LOT, _GNC_MOD_NAME,
    2243                 :             :             (QofAccessFunc)gncInvoiceGetInvoiceFromLot, NULL
    2244                 :             :         },
    2245                 :             :         { NULL },
    2246                 :             :     };
    2247                 :             : 
    2248                 :          84 :     qof_class_register (GNC_ID_LOT, NULL, params);
    2249                 :          84 : }
    2250                 :             : 
    2251                 :             : static void
    2252                 :          84 : reg_txn (void)
    2253                 :             : {
    2254                 :             :     static QofParam params[] =
    2255                 :             :     {
    2256                 :             :         {
    2257                 :             :             INVOICE_FROM_TXN, _GNC_MOD_NAME,
    2258                 :             :             (QofAccessFunc)gncInvoiceGetInvoiceFromTxn, NULL
    2259                 :             :         },
    2260                 :             :         { NULL },
    2261                 :             :     };
    2262                 :             : 
    2263                 :          84 :     qof_class_register (GNC_ID_TRANS, NULL, params);
    2264                 :          84 : }
    2265                 :             : 
    2266                 :          84 : gboolean gncInvoiceRegister (void)
    2267                 :             : {
    2268                 :             :     static QofParam params[] =
    2269                 :             :     {
    2270                 :             :         { INVOICE_ID,        QOF_TYPE_STRING,  (QofAccessFunc)gncInvoiceGetID,     (QofSetterFunc)gncInvoiceSetID },
    2271                 :             :         { INVOICE_OWNER,     GNC_ID_OWNER,     (QofAccessFunc)gncInvoiceGetOwner, NULL },
    2272                 :             :         { INVOICE_OPENED,    QOF_TYPE_DATE,    (QofAccessFunc)gncInvoiceGetDateOpened, (QofSetterFunc)gncInvoiceSetDateOpened },
    2273                 :             :         { INVOICE_DUE,       QOF_TYPE_DATE,    (QofAccessFunc)gncInvoiceGetDateDue, NULL },
    2274                 :             :         { INVOICE_POSTED,    QOF_TYPE_DATE,    (QofAccessFunc)gncInvoiceGetDatePosted, (QofSetterFunc)gncInvoiceSetDatePosted },
    2275                 :             :         { INVOICE_IS_POSTED, QOF_TYPE_BOOLEAN, (QofAccessFunc)gncInvoiceIsPosted, NULL },
    2276                 :             :         { INVOICE_IS_PAID,   QOF_TYPE_BOOLEAN, (QofAccessFunc)gncInvoiceIsPaid,    NULL },
    2277                 :             :         { INVOICE_BILLINGID, QOF_TYPE_STRING,  (QofAccessFunc)gncInvoiceGetBillingID, (QofSetterFunc)gncInvoiceSetBillingID },
    2278                 :             :         { INVOICE_NOTES,     QOF_TYPE_STRING,  (QofAccessFunc)gncInvoiceGetNotes,   (QofSetterFunc)gncInvoiceSetNotes },
    2279                 :             :         { INVOICE_DOCLINK, QOF_TYPE_STRING, (QofAccessFunc)gncInvoiceGetDocLink, (QofSetterFunc)gncInvoiceSetDocLink },
    2280                 :             :         { INVOICE_ACC,       GNC_ID_ACCOUNT,   (QofAccessFunc)gncInvoiceGetPostedAcc, (QofSetterFunc)gncInvoiceSetPostedAcc },
    2281                 :             :         { INVOICE_POST_TXN,  GNC_ID_TRANS,     (QofAccessFunc)gncInvoiceGetPostedTxn, (QofSetterFunc)gncInvoiceSetPostedTxn },
    2282                 :             :         { INVOICE_POST_LOT,  GNC_ID_LOT,       (QofAccessFunc)gncInvoiceGetPostedLot, NULL/*(QofSetterFunc)gncInvoiceSetPostedLot*/ },
    2283                 :             :         { INVOICE_TYPE,      QOF_TYPE_INT32,   (QofAccessFunc)gncInvoiceGetType,    NULL },
    2284                 :             :         { INVOICE_TYPE_STRING, QOF_TYPE_STRING, (QofAccessFunc)gncInvoiceGetTypeString,    NULL },
    2285                 :             :         { INVOICE_TERMS,     GNC_ID_BILLTERM,  (QofAccessFunc)gncInvoiceGetTerms,   (QofSetterFunc)gncInvoiceSetTerms },
    2286                 :             :         { INVOICE_BILLTO,    GNC_ID_OWNER,     (QofAccessFunc)gncInvoiceGetBillTo, NULL  },
    2287                 :             :         { INVOICE_ENTRIES,   QOF_TYPE_COLLECT, (QofAccessFunc)qofInvoiceGetEntries, (QofSetterFunc)qofInvoiceSetEntries },
    2288                 :             :         { INVOICE_JOB,       GNC_ID_JOB,       (QofAccessFunc)qofInvoiceGetJob,     (QofSetterFunc)qofInvoiceSetJob },
    2289                 :             :         { QOF_PARAM_ACTIVE,  QOF_TYPE_BOOLEAN, (QofAccessFunc)gncInvoiceGetActive, (QofSetterFunc)gncInvoiceSetActive },
    2290                 :             :         { INVOICE_IS_CN,     QOF_TYPE_BOOLEAN, (QofAccessFunc)gncInvoiceGetIsCreditNote, (QofSetterFunc)gncInvoiceSetIsCreditNote },
    2291                 :             :         { QOF_PARAM_BOOK,    QOF_ID_BOOK,      (QofAccessFunc)qof_instance_get_book, NULL },
    2292                 :             :         { QOF_PARAM_GUID,    QOF_TYPE_GUID,    (QofAccessFunc)qof_instance_get_guid, NULL },
    2293                 :             :         { NULL },
    2294                 :             :     };
    2295                 :             : 
    2296                 :          84 :     qof_class_register (_GNC_MOD_NAME, (QofSortFunc)gncInvoiceCompare, params);
    2297                 :          84 :     reg_lot ();
    2298                 :          84 :     reg_txn ();
    2299                 :             : 
    2300                 :             :     /* Make the compiler happy... */
    2301                 :             :     if (0)
    2302                 :             :     {
    2303                 :             :         qofInvoiceSetEntries (NULL, NULL);
    2304                 :             :         qofInvoiceGetEntries (NULL);
    2305                 :             :         qofInvoiceSetOwner (NULL, NULL);
    2306                 :             :         qofInvoiceGetOwner (NULL);
    2307                 :             :         qofInvoiceSetBillTo (NULL, NULL);
    2308                 :             :         qofInvoiceGetBillTo (NULL);
    2309                 :             :     }
    2310                 :          84 :     return qof_object_register (&gncInvoiceDesc);
    2311                 :             : }
    2312                 :             : 
    2313                 :           0 : gchar *gncInvoiceNextID (QofBook *book, const GncOwner *owner)
    2314                 :             : {
    2315                 :             :     gchar *nextID;
    2316                 :           0 :     switch (gncOwnerGetType (gncOwnerGetEndOwner (owner)))
    2317                 :             :     {
    2318                 :           0 :     case GNC_OWNER_CUSTOMER:
    2319                 :           0 :         nextID = qof_book_increment_and_format_counter (book, "gncInvoice");
    2320                 :           0 :         break;
    2321                 :           0 :     case GNC_OWNER_VENDOR:
    2322                 :           0 :         nextID = qof_book_increment_and_format_counter (book, "gncBill");
    2323                 :           0 :         break;
    2324                 :           0 :     case GNC_OWNER_EMPLOYEE:
    2325                 :           0 :         nextID = qof_book_increment_and_format_counter (book, "gncExpVoucher");
    2326                 :           0 :         break;
    2327                 :           0 :     default:
    2328                 :           0 :         nextID = qof_book_increment_and_format_counter (book, _GNC_MOD_NAME);
    2329                 :           0 :         break;
    2330                 :             :     }
    2331                 :           0 :     return nextID;
    2332                 :             : }
        

Generated by: LCOV version 2.0-1