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
This commit is contained in:
Geert Janssens
2012-05-08 11:39:09 +00:00
parent dbcd08db01
commit e7a2a8fbcb
6 changed files with 126 additions and 53 deletions

View File

@@ -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 ();

View File

@@ -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);

View File

@@ -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);

View File

@@ -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)
{

View File

@@ -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);

View File

@@ -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, \