From e7a2a8fbcb87ffa52332e05789fc4dd05bb47657 Mon Sep 17 00:00:00 2001 From: Geert Janssens Date: Tue, 8 May 2012 11:39:09 +0000 Subject: [PATCH] Add gnc{Owner,Invoice}ApplyPayment functions. Most payment use cases don't need to know the internal lot juggling mechanism behind it. git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@22174 57a11ea4-9604-0410-9ed3-97b8803252fd --- src/business/business-gnome/dialog-payment.c | 38 ++--------- src/engine/gncInvoice.c | 33 ++++++++++ src/engine/gncInvoice.h | 19 ++++++ src/engine/gncOwner.c | 66 ++++++++++++++----- src/engine/gncOwner.h | 21 +++++- .../python-bindings/gnucash_business.py | 2 +- 6 files changed, 126 insertions(+), 53 deletions(-) diff --git a/src/business/business-gnome/dialog-payment.c b/src/business/business-gnome/dialog-payment.c index 2c1a884cd5..970f6a8d0a 100644 --- a/src/business/business-gnome/dialog-payment.c +++ b/src/business/business-gnome/dialog-payment.c @@ -210,28 +210,6 @@ gnc_payment_dialog_document_selection_changed (PaymentWindow *pw) gnc_ui_payment_window_set_amount(pw, gnc_numeric_abs (val)); } -static gboolean -gnc_lot_match_owner (GNCLot *lot, gpointer user_data) -{ - const GncOwner *req_owner = user_data; - GncOwner lot_owner; - const GncOwner *end_owner; - GncInvoice *invoice = gncInvoiceGetInvoiceFromLot (lot); - - /* Determine the owner associated to the lot */ - if (invoice) - /* Invoice lots */ - end_owner = gncOwnerGetEndOwner (gncInvoiceGetOwner (invoice)); - else if (gncOwnerGetOwnerFromLot (lot, &lot_owner)) - /* Pre-payment lots */ - end_owner = gncOwnerGetEndOwner (&lot_owner); - else - return FALSE; - - /* Is this a lot for the requested owner ? */ - return gncOwnerEqual (end_owner, req_owner); -} - static void gnc_payment_window_fill_docs_list (PaymentWindow *pw) { @@ -242,7 +220,7 @@ gnc_payment_window_fill_docs_list (PaymentWindow *pw) /* Get a list of open lots for this owner and post account */ if (pw->owner.owner.undefined) - list = xaccAccountFindOpenLots (pw->post_acct, gnc_lot_match_owner, + list = xaccAccountFindOpenLots (pw->post_acct, gncOwnerLotMatchOwnerFunc, &pw->owner, NULL); /* Clear the existing list */ @@ -630,17 +608,9 @@ gnc_payment_ok_cb (GtkWidget *widget, gpointer data) gnc_xfer_dialog_run_until_done(xfer); } - /* Create a lot for this payment */ - payment_lot = gncOwnerCreatePaymentLot (&pw->owner, pw->pre_existing_txn, - post, acc, amount, exch, date, memo, num); - - /* And link the selected lots and the payment lot together as well as possible. - * If the payment was bigger than the selected documents/overpayments, only - * part of the payment will be used. Similarly if more documents were selected - * than the payment value set, not all documents will be marked as paid. */ - if (payment_lot) - selected_lots = g_list_prepend (selected_lots, payment_lot); - gncOwnerAutoApplyPaymentsWithLots (&pw->owner, selected_lots); + /* Perform the payment */ + gncOwnerApplyPayment (&pw->owner, pw->pre_existing_txn, selected_lots, + post, acc, amount, exch, date, memo, num); } gnc_resume_gui_refresh (); diff --git a/src/engine/gncInvoice.c b/src/engine/gncInvoice.c index 2b5628cd37..662fb1523a 100644 --- a/src/engine/gncInvoice.c +++ b/src/engine/gncInvoice.c @@ -1700,6 +1700,39 @@ void gncInvoiceAutoApplyPayments (GncInvoice *invoice) g_list_free (lot_list); } +/* + * Create a payment of "amount" for the invoice owner and attempt + * to balance it with the given invoice. + */ +void +gncInvoiceApplyPayment (const GncInvoice *invoice, Transaction *txn, + Account *xfer_acc, gnc_numeric amount, + gnc_numeric exch, Timespec date, + const char *memo, const char *num) +{ + GNCLot *payment_lot, *invoice_lot; + GList *selected_lots = NULL; + const GncOwner *owner; + + /* Verify our arguments */ + if (!invoice || !gncInvoiceIsPosted (invoice) || !xfer_acc) return; + + owner = gncOwnerGetEndOwner (gncInvoiceGetOwner (invoice)); + g_return_if_fail (owner->owner.undefined); + + /* Create a lot for this payment */ + payment_lot = gncOwnerCreatePaymentLot (owner, txn, invoice->posted_acc, xfer_acc, + amount, exch, date, memo, num); + + /* Select the invoice as only payment candidate */ + selected_lots = g_list_prepend (selected_lots, invoice->posted_lot); + + /* And link the invoice lot and the payment lot together as well as possible. */ + if (payment_lot) + selected_lots = g_list_prepend (selected_lots, payment_lot); + gncOwnerAutoApplyPaymentsWithLots (owner, selected_lots); +} + static gboolean gncInvoiceDateExists (const Timespec *date) { g_return_val_if_fail (date, FALSE); diff --git a/src/engine/gncInvoice.h b/src/engine/gncInvoice.h index 18d49ebd29..c361e14567 100644 --- a/src/engine/gncInvoice.h +++ b/src/engine/gncInvoice.h @@ -204,6 +204,25 @@ gncInvoiceUnpost (GncInvoice *invoice, gboolean reset_tax_tables); void gncInvoiceAutoApplyPayments (GncInvoice *invoice); +/** + * A convenience function to apply a payment to an invoice. + * It creates a lot for a payment optionally based on an existing + * transaction and then tries to balance it with + * the given invoice. + * Contrary to gncOwnerApplyPayment, no other open documents + * or payments for the owner will be considered + * to balance the payment. + * + * This code is actually a convenience wrapper around gncOwnerCreatePaymentLot + * and gncOwnerAutoApplyPaymentsWithLots. See their descriptions for more + * details on what happens exactly. + */ +void +gncInvoiceApplyPayment (const GncInvoice *invoice, Transaction *txn, + Account *xfer_acc, gnc_numeric amount, + gnc_numeric exch, Timespec date, + const char *memo, const char *num); + /** Given a transaction, find and return the Invoice */ GncInvoice * gncInvoiceGetInvoiceFromTxn (const Transaction *txn); diff --git a/src/engine/gncOwner.c b/src/engine/gncOwner.c index 7a65c2212f..11566f9ac4 100644 --- a/src/engine/gncOwner.c +++ b/src/engine/gncOwner.c @@ -659,26 +659,23 @@ KvpFrame* gncOwnerGetSlots(GncOwner* owner) gboolean gncOwnerLotMatchOwnerFunc (GNCLot *lot, gpointer user_data) { - GncOwner owner_def; - const GncOwner *owner; - const GncOwner *this_owner = user_data; - GncInvoice *invoice; + const GncOwner *req_owner = user_data; + GncOwner lot_owner; + const GncOwner *end_owner; + GncInvoice *invoice = gncInvoiceGetInvoiceFromLot (lot); - /* If this lot is not for this owner, then ignore it */ - invoice = gncInvoiceGetInvoiceFromLot (lot); + /* Determine the owner associated to the lot */ if (invoice) - { - owner = gncInvoiceGetOwner (invoice); - owner = gncOwnerGetEndOwner ((GncOwner*)owner); - } + /* Invoice lots */ + end_owner = gncOwnerGetEndOwner (gncInvoiceGetOwner (invoice)); + else if (gncOwnerGetOwnerFromLot (lot, &lot_owner)) + /* Pre-payment lots */ + end_owner = gncOwnerGetEndOwner (&lot_owner); else - { - if (!gncOwnerGetOwnerFromLot (lot, &owner_def)) - return FALSE; - owner = gncOwnerGetEndOwner (&owner_def); - } + return FALSE; - return gncOwnerEqual (owner, this_owner); + /* Is this a lot for the requested owner ? */ + return gncOwnerEqual (end_owner, req_owner); } gint @@ -1024,6 +1021,43 @@ void gncOwnerAutoApplyPaymentsWithLots (const GncOwner *owner, GList *lots) } } +/* + * Create a payment of "amount" for the owner and match it with + * the set of lots passed in. If not lots were given all open + * lots for the owner are considered. + */ +void +gncOwnerApplyPayment (const GncOwner *owner, Transaction *txn, GList *lots, + Account *posted_acc, Account *xfer_acc, + gnc_numeric amount, gnc_numeric exch, Timespec date, + const char *memo, const char *num) +{ + GNCLot *payment_lot; + GList *selected_lots; + + /* Verify our arguments */ + if (!owner || !posted_acc || !xfer_acc) return; + g_return_if_fail (owner->owner.undefined); + + /* Create a lot for this payment */ + payment_lot = gncOwnerCreatePaymentLot (owner, txn, posted_acc, xfer_acc, + amount, exch, date, memo, num); + + if (lots) + selected_lots = lots; + else + selected_lots = xaccAccountFindOpenLots (posted_acc, gncOwnerLotMatchOwnerFunc, + (gpointer)owner, NULL); + + /* And link the selected lots and the payment lot together as well as possible. + * If the payment was bigger than the selected documents/overpayments, only + * part of the payment will be used. Similarly if more documents were selected + * than the payment value set, not all documents will be marked as paid. */ + if (payment_lot) + selected_lots = g_list_prepend (selected_lots, payment_lot); + gncOwnerAutoApplyPaymentsWithLots (owner, selected_lots); +} + GList * gncOwnerGetAccountTypesList (const GncOwner *owner) { diff --git a/src/engine/gncOwner.h b/src/engine/gncOwner.h index ce1f2c2074..c60ef2e3fa 100644 --- a/src/engine/gncOwner.h +++ b/src/engine/gncOwner.h @@ -201,8 +201,8 @@ gboolean gncOwnerGetOwnerFromTypeGuid (QofBook *book, GncOwner *owner, QofIdType KvpFrame* gncOwnerGetSlots(GncOwner* owner); /** - * Create a lot for a payment for the given owner and with the given - * parameters. If a transaction is passed, this transaction will be + * Create a lot for a payment to the owner using the other + * parameters passed in. If a transaction is set, this transaction will be * reused if possible (meaning, if the transaction currency matches * the owner's currency and if the transaction has (at least?) one * split in the transfer account). @@ -249,6 +249,23 @@ gncOwnerCreatePaymentLot (const GncOwner *owner, Transaction *txn, */ void gncOwnerAutoApplyPaymentsWithLots (const GncOwner *owner, GList *lots); +/** + * A convenience function to apply a payment to the owner. + * It creates a lot for a payment, optionally based on an existing + * transaction and then tries to balance it with the list of + * document/payment lots passed in. If not lots were given, + * all open lots for the owner are considered. + * + * This code is actually a convenience wrapper around gncOwnerCreatePaymentLot + * and gncOwnerAutoApplyPaymentsWithLots. See their descriptions for more + * details on what happens exactly. + */ +void +gncOwnerApplyPayment (const GncOwner *owner, Transaction *txn, GList *lots, + Account *posted_acc, Account *xfer_acc, + gnc_numeric amount, gnc_numeric exch, Timespec date, + const char *memo, const char *num); + /** Returns a GList of account-types based on the owner type */ GList * gncOwnerGetAccountTypesList (const GncOwner *owner); diff --git a/src/optional/python-bindings/gnucash_business.py b/src/optional/python-bindings/gnucash_business.py index bb379af73f..8e404a9ca4 100644 --- a/src/optional/python-bindings/gnucash_business.py +++ b/src/optional/python-bindings/gnucash_business.py @@ -38,7 +38,7 @@ from gnucash_core import \ Split, Book, GncLot, Account from gnucash_core_c import GNC_OWNER_CUSTOMER, GNC_OWNER_JOB, \ - GNC_OWNER_EMPLOYEE, GNC_OWNER_VENDOR, gncOwnerCreatePaymentLot, \ + GNC_OWNER_EMPLOYEE, GNC_OWNER_VENDOR, \ GNC_PAYMENT_CASH, GNC_PAYMENT_CARD, \ GNC_DISC_PRETAX, GNC_DISC_SAMETIME, GNC_DISC_POSTTAX, \ GNC_TAXINCLUDED_YES, GNC_TAXINCLUDED_NO, GNC_TAXINCLUDED_USEGLOBAL, \