Submit a payment from somewhere not in the GUI...

Geert Janssens geert.gnucash at kobaltwit.be
Mon Nov 17 12:12:08 EST 2014


On Friday 14 November 2014 20:35:47 Tom Lofts wrote:
> Hi Allen,
> 
> As part of some of the work I've been doing to create a REST like API
> via the Python bindings I've also been trying to make payments via the
> Python API.
> 
> I think I've managed to find out how this is intended to be done but
> can't quite get it to work.
> 
> The relevant function in the GnuCash core is I believe is
> gncOwnerApplyPayment.

gncOwnerApplyPayment is one option. The other is gncInvoiceApplyPayment. The former is the 
most generic one, the latter is a convenience function that lets you apply a payment to one 
specific invoice.

> This isn't exposed in the Python bindings, so I
> add it to the Customer object with (I can provide an example file with
> this in, but don't have a clean version of the code at the moment):
> 
> gnucash.gnucash_business.Customer.add_method('gncOwnerApplyPayment',
> 'ApplyPayment')
> 
This function *is* exposed in the Python bindings, at least in 2.6.x and master.

It is added to the Customer object via its parent class. There should be no need to explicitly use 
add_method.
You can look at simple_business_create.py to learn how it's used.
Note that there have been a couple of API changes in this area between 2.4.x and 2.6.x. As a 
result simple_business_create.py as currently released will fail. I have just pushed a few fixes to 
the python bindings to deal with this. In short the functions now requires an additional boolean 
parameter "AutoPay".

> I also use xaccAccountGetLotList (as it's the lots parameter I'm
> having problems with)
> 
> gnucash.gnucash_core.Account.add_method('xaccAccountGetLotList',
> 'GetLotList')
> 
xaccAccountGetLotList will return a GList * of lots. It is however not what 
gncOwnerApplyPayment is expecting as input. Those are way to many lots.

The background behind the lot list that is passed to the function is this:
In the gui payment dialog a user can select one or more invoices and pre-payments and an 
additional payment amount. The invoices and pre-payments all have their own lot assigned to 
them. The lots for all selected invoices and pre-payments form the list that gets passed to 
gncOwnerApplyPayment. That function will try to offset the invoices with the pre-payments and 
the final payment amount.
If the user hadn't selected any invoice or pre-payment the lot list would be empty and nothing 
would happen. However by setting the new parameter AutoPay to True, the function will look up 
all open invoices and pre-payments for the customer and try to offset the found list to the 
payment amount the user has given.
So you can use this function without a lot list if you set the AutoPay parameter to True and the 
lot list set to None. In that case your invoices will get paid in a first-in-first-out order.
The lot list is only required if you explicitly want to apply a payment to a specific (set of) 
invoices.

As mentioned before gncInvoiceApplyPayment is a convenience function that allows you to 
select one invoice to apply the payment to. You could use this if the goal is to pay one specific 
invoice.

In all other cases you will have to assemble a list of lots that should be handled by the payment.

> Then attempt to use the following (please note I've hardcoded the
> GUIDs used for the accounts:
> 
> session = gnucash.Session(arguments[0], ignore_lock=True)
> 
> invoice = session.book.InvoiceLookupByID('000001')
> customer = invoice.GetOwner()
> 
> transaction = invoice.GetPostedTxn()
> lot = invoice.GetPostedLot()
> 
> account_guid = gnucash.gnucash_core.GUID()
> gnucash.gnucash_core.GUIDString('6ab0f12d91e944d00a2ffa0588e252e6',
> account_guid) # AR
> 
> posted_acc = account_guid.AccountLookup(session.book)
> 
> account_guid2 = gnucash.gnucash_core.GUID()
> gnucash.gnucash_core.GUIDString('1886b76bb07786f2a821356d928ec461',
> account_guid2) # Liabilities: CC
> 
> xfer_acc = account_guid2.AccountLookup(session.book)
> 
> customer.ApplyPayment(transaction, posted_acc.GetLotList(),
> posted_acc, xfer_acc, invoice.GetTotal(), GncNumeric(0),
> datetime.datetime.strptime('2014-08-11', '%Y-%m-%d'), '', '', False)
> 
> Unfortunately this fails with the error:
> 
> Traceback (most recent call last):
>    File "gnucash_rest.py", line 1622, in <module>
>      customer.ApplyPayment(transaction, posted_acc.GetLotList(),
> posted_acc, xfer_acc, invoice.GetTotal(), GncNumeric(0),
> datetime.datetime.strptime('2014-08-11', '%Y-%m-%d'), '', '', False)
>    File
> "/usr/local/lib/python2.7/dist-packages/gnucash/function_class.py",
> line 91, in method_function
>      *process_list_convert_to_instance(meth_func_args) )
>    File
> "/usr/local/lib/python2.7/dist-packages/gnucash/gnucash_core_c.py",
> line 2922, in gncOwnerApplyPayment
>      return _gnucash_core_c.gncOwnerApplyPayment(*args)
> TypeError: in method 'gncOwnerApplyPayment', argument 3 of type 'GList
> *'
> 
I don't know exactly why this is happening I'm afraid either. Presumably GetLotList returns a 
python type list while you should pass the function a real GList. I have no experience either 
though in how this conversion should happen.

Geert


More information about the gnucash-devel mailing list