gnucash master: - REST API Example for Python Bindings #2
John Ralls
jralls at code.gnucash.org
Mon Jan 5 22:19:42 EST 2015
Updated via https://github.com/Gnucash/gnucash/commit/c27bea60 (commit)
from https://github.com/Gnucash/gnucash/commit/39b4034e (commit)
commit c27bea603132b4b0d3ca82b324dcfe12b46814f9
Author: Tom Lofts <dev at loftx.co.uk>
Date: Sun Jan 4 00:52:05 2015 +0000
- REST API Example for Python Bindings #2
Enhancements include:
- manipulation of transactions, splits, vendors and bills
- add and edit functionality customers and invoices
Author: Tom Lofts <dev at loftx.co.uk>
diff --git a/src/optional/python-bindings/example_scripts/rest-api/README b/src/optional/python-bindings/example_scripts/rest-api/README
index b15d8dd..393035f 100644
--- a/src/optional/python-bindings/example_scripts/rest-api/README
+++ b/src/optional/python-bindings/example_scripts/rest-api/README
@@ -1,48 +1,218 @@
A Python based REST framework for the Gnucash accounting application
-**Please note this is a very early work in progress and should not be run against live or production data.**
-
-This project is designed to allow other applications to easily extract (and hopefully insert and update at some point) data from Gnucash via a RESTful API.
-
-The API is built on the existing Python bindings and uses Flask to serve responses in JSON.
-
-Currently only accounts, customers and invoices can be accessed via the framework
-
-Accounts: <http://localhost:5000/accounts>
-Individual accounr: <http://localhost:5000/accounts/XXXX>
-
-Invoices: <http://localhost:5000/invoices>
-Individual invoice: <http://localhost:5000/invoices/XXXX>
-
-Customers: <http://localhost:5000/customers>
-Individual customer: <http://localhost:5000/customers/XXXX>
-
-Invoices can be filtered via the following parameters:
-
-is_active 1 or 0
-is_paid 1 or 0
-
-e.g. <http://localhost:5000/invoices?is_active=1&is_paid=0>
+**Please note this is a very early work in progress and should not be run
+against live or production data.**
+
+This project is designed to allow other applications to easily interact with
+data from Gnucash via a RESTful API.
+
+The API is built on the existing Python bindings and uses Flask to serve
+responses in JSON.
+
+Currently accounts, transactions, splits, customers, vendors, invoices and
+bills can be accessed to some degree via the framework:
+
+Accounts:
+
+GET request to /accounts - returns a complete list of accounts
+GET request to /accounts/<guid> - returns an individual account
+GET request to /accounts/<guid>/splits - returns splits for an individual
+account
+
+POST request to /transactions - creates a new transaction (currently with only
+two splits)
+
+POST variables:
+currency - required - a gnucash currency code e.g. GBP
+description - required - a description for the transaction
+num - optional - a transaction number
+date_posted - required - a date formatted as YYYY-MM-DD
+splitvalue1 - required - the value of the split on splitaccount1
+splitaccount1 - required - the GUID for the 1st account on this transaction
+(can be obtained from /accounts)
+splitvalue2 - required - the value of the split on splitaccount2
+splitaccount2 - required - the GUID for the 2nd account on this transaction
+
+GET request to /transactions/<guid> - returns an individual transaction
+POST request to /transactions/<guid> - edits an existing transaction (accepts
+the same post variables as /transactions)
+DELETE request to /transactions/<guid> - deletes a transaction
+
+GET request to /bills - returns a list of bills
+
+GET variables:
+is_paid - optional - 1 returns paid bills, 0 unpaid
+is_active - optional - 1 returns active bills, 0 inactive
+date_opened_from - optional - all transactions on and after a date formatted
+as YYYY-MM-DD
+date_opened_to - optional - all transactions up to and before a date formatted
+as YYYY-MM-DD
+
+POST request to /bills - creates a new bill
+
+POST variables:
+id - optional - if no id is specified the next available sequential id will be
+used
+vendor_id - required - the id of the vendor of this bill (can be obtained from
+/vendors)
+currency - required - a gnucash currency code
+date_opened - required - a date formatted as YYYY-MM-DD
+notes - optional - notes for this bill
+
+GET request to /bills/<id> - returns an individual bill
+POST request to /bills/<id> - edits (and optionally posts) a bill
+
+POST variables:
+vendor_id - required - the id of the vendor of this bill (can be obtained from
+/vendors)
+currency - required - a gnucash currency code
+date_opened - a date formatted as YYYY-MM-DD
+notes - optional - notes for this invoice
+posted - optional - set to 1 if marking the invoice as posted (0 or empty
+otherwise)
+posted_account_guid - required if posted = 1 - the GUID for the posted account
+posted_date - required if posted = 1 - a date formatted as YYYY-MM-DD
+due_date - required if posted = 1 - a date formatted as YYYY-MM-DD
+posted_memo - optional - a description
+posted_accumulatesplits - optional - whether to accumulate splits or not (1 for
+yes, 0 for no)
+posted_autopay - optional - whether to auto pay or not (1 for yes, 0 for no)
+
+PAY request to /bills/<id> - mark a bill as paid
+
+POST variables:
+
+posted_account_guid - required - the GUID for the posted account
+transfer_account_guid - required - the GUID for the transfer account
+payment_date - required - a date formatted as YYYY-MM-DD
+num - optional - a number for this payment
+memo - optional - a description for this payment
+auto_pay - required - whether to auto pay or not (1 for yes, 0 for no)
+
+GET request to /bills/<id>/entries - return all entries for an individual bill
+POST request to /bills/<id>/entries - adds a new entry to a bill
+
+date - required - a date formatted as YYYY-MM-DD
+description - required - the description for this entry
+account_guid - required - the GUID for the required accoumt
+quantity - required - the quantity
+price - required - the price
+
+GET request to /invoices - returns all invoices (accepts the same get variables
+as /bills)
+POST request to /invoices - creates a new invoice
+
+POST variables:
+id - optional - if no id is specified the next available sequential id will be
+used
+customer_id - required - the id of the customer of this invoice (can be
+obtained from /customers)
+currency - required - a gnucash currency code
+date_opened - a date formatted as YYYY-MM-DD
+notes - optional - notes for this invoice
+
+GET request to /invoices/<id> - returns an individual invoice
+POST request to /invoices/<id> - edits (and optionally posts) an invoice
+
+POST variables:
+customer_id - required - the id of the customer of this bill (can be obtained
+from /customers)
+currency - required - a gnucash currency code
+date_opened - a date formatted as YYYY-MM-DD
+notes - optional - notes for this invoice
+posted - optional - set to 1 if marking the invoice as posted (0 or empty
+otherwise)
+posted_account_guid - required if posted = 1 - the GUID for the posted account
+posted_date - required if posted = 1 - a date formatted as YYYY-MM-DD
+due_date - required if posted = 1 - a date formatted as YYYY-MM-DD
+posted_memo - optional - a description
+posted_accumulatesplits - optional - whether to accumulate splits or not (1 for
+yes, 0 for no)
+posted_autopay - optional - whether to auto pay or not (1 for yes, 0 for no)
+
+PAY request to /invoices/<id> - mark an invoice as paid (accepts the same post
+variables as /bills/<id>)
+
+GET request to /invoices/<id>/entries - return all entries for an individual
+invoice
+POST request to /invoices/<id>/entries - adds a new entry to an invoice
+(accepts the same post variables as /bills/<id>/entries)
+
+GET request to /entries/<guid> - returns an individual entry
+POST request to /entries/<guid> - edits an existing entry (accepts the same
+post variables as /bills/<id>/entries)
+
+GET request to /customers - returns a list of customers
+POST request to /customers - creates a new customer
+
+POST variables:
+id - optional - if no id is specified the next available sequential id will be
+used
+currency - required - a gnucash currency code
+name - required - the customer's name
+contact - optional - a contact for this customer
+address_line_1 - required - the first line of the customer's address
+address_line_2 - optional - the second line of the customer's address
+address_line_3 - optional - the third line of the customer's address
+address_line_4 - optional - the fourth line of the customer's address
+phone - optional - the customer's phone number
+fax - optional - the customer's fax number
+email - optional - the customer's email address
+
+GET request to /customers/<id> - returns an individual customer
+POST request to /customers/<id> - edits an existing customer (accepts the same
+post variables as /customers)
+GET request to /customers/<id>/invoices - returns all invoices for a single
+customer
+
+GET request to /vendors - returns a list of vendors
+POST request to /vendors - creates a new vendor
+
+POST variables:
+id - optional - if no id is specified the next available sequential id will be
+used
+currency - required - a gnucash currency code
+name - required - the vendor's name
+contact - optional - a contact for this vendor
+address_line_1 - required - the first line of the vendor's address
+address_line_2 - optional - the second line of the vendor's address
+address_line_3 - optional - the third line of the vendor's address
+address_line_4 - optional - the fourth line of the vendor's address
+phone - optional - the vendor's phone number
+fax - optional - the vendor's fax number
+email - optional - the vendor's email address
+
+GET request to /vendors/<id> - returns an individual vendor
+GET request to /vendors/<id>/bills - returns all bills for a single vendor
Usage
-----
-**As this is work in progress you'll need a knowledge of building Gnucash from source and experience with python.**
+**As this is work in progress you'll need a knowledge of building Gnucash from
+source and experience with python.**
-Full details to be provided at a later date, but in short you'll need a copy of Gnucash built with Python bindings and the Flask module installed.
+Full details to be provided at a later date, but in short you'll need a copy of
+Gnucash built with Python bindings and the Flask module installed.
-Rrun `python ./gnucash_rest <connection string>` to start the server on <http://localhost:5000> e.g `python ./gnucash_rest mysql://user:password@127.0.0.1/gnucash_test`
+Rrun `python ./gnucash_rest <connection string>` to start the server on
+<http://localhost:5000> e.g
+`python ./gnucash_rest mysql://user:password@127.0.0.1/gnucash_test`
-Navigate to <http://localhost:5000/invoices> and you should get your invoices in JSON format.
+Navigate to <http://localhost:5000/invoices> and you should get your invoices
+in JSON format.
Files
-----
-`gnucash_rest.py` - The Flask app which responds to REST requests with JSON responses
+`gnucash_rest.py` - The Flask app which responds to REST requests with JSON
+responses
-`gnucash_simple.py` - A helper file to convert Gnucash objects into dictionaries for easier conversion to JSON.
+`gnucash_simple.py` - A helper file to convert Gnucash objects into
+dictionaries for easier conversion to JSON.
Future
------
-I'm using the API already to integrate Gnucash invoices with other systems, so I'll be adding features as and when I need them. The format of the API is likely to change as development continues.
+I'm using the API already to integrate Gnucash invoices with other systems, so
+I'll be adding features as and when I need them. The format of the API is
+likely to change as development continues.
diff --git a/src/optional/python-bindings/example_scripts/rest-api/gnucash_rest.py b/src/optional/python-bindings/example_scripts/rest-api/gnucash_rest.py
old mode 100755
new mode 100644
index 2e21586..f6a4dc9
--- a/src/optional/python-bindings/example_scripts/rest-api/gnucash_rest.py
+++ b/src/optional/python-bindings/example_scripts/rest-api/gnucash_rest.py
@@ -1,13 +1,48 @@
#!/usr/bin/python
+'''
+
+gnucash_rest.py -- A Flask app which responds to REST requests
+with JSON responses
+
+Copyright (C) 2013 Tom Lofts <dev at loftx.co.uk>
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of
+the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, contact:
+
+Free Software Foundation Voice: +1-617-542-5942
+51 Franklin Street, Fifth Floor Fax: +1-617-542-2652
+Boston, MA 02110-1301, USA gnu at gnu.org
+
+ at author Tom Lofts <dev at loftx.co.uk>
+
+'''
+
import gnucash
import gnucash_simple
import json
import atexit
-from flask import Flask, abort, request
+from flask import Flask, abort, request, Response
import sys
import getopt
+from decimal import Decimal
+
+from gnucash.gnucash_business import Vendor, Bill, Entry, GncNumeric, \
+ Customer, Invoice, Split, Account, Transaction
+
+import datetime
+
from gnucash import \
QOF_QUERY_AND, \
QOF_QUERY_OR, \
@@ -36,185 +71,1842 @@ from gnucash import \
app = Flask(__name__)
app.debug = True
- at app.route('/accounts')
+ at app.route('/accounts', methods=['GET', 'POST'])
def api_accounts():
- accounts = getAccounts(session.book)
+ if request.method == 'GET':
- return accounts
+ accounts = getAccounts(session.book)
- at app.route('/accounts/<guid>')
-def api_account(guid):
+ return Response(json.dumps(accounts), mimetype='application/json')
+
+ elif request.method == 'POST':
- account = getAccount(session.book, guid)
+ try:
+ account = addAccount(session.books)
+ except Error as error:
+ return Response(json.dumps({'errors': [{'type' : error.type,
+ 'message': error.message, 'data': error.data}]}), status=400,
+ mimetype='application/json')
+ else:
+ return Response(json.dumps(account), status=201,
+ mimetype='application/json')
- if account is None:
- abort(404)
- else:
- return account
+ else:
+ abort(405)
- at app.route('/invoices')
+ at app.route('/accounts/<guid>', methods=['GET'])
+def api_account(guid):
+
+ account = getAccount(session.book, guid)
+
+ if account is None:
+ abort(404)
+ else:
+ return Response(json.dumps(account), mimetype='application/json')
+
+ at app.route('/accounts/<guid>/splits', methods=['GET'])
+def api_account_splits(guid):
+
+ date_posted_from = request.args.get('date_posted_from', None)
+ date_posted_to = request.args.get('date_posted_to', None)
+
+ # check account exists
+ account = getAccount(session.book, guid)
+
+ if account is None:
+ abort(404)
+
+ splits = getAccountSplits(session.book, guid, date_posted_from,
+ date_posted_to)
+
+ return Response(json.dumps(splits), mimetype='application/json')
+
+
+ at app.route('/transactions', methods=['POST'])
+def api_transactions():
+
+ if request.method == 'POST':
+
+ currency = str(request.form.get('currency', ''))
+ description = str(request.form.get('description', ''))
+ num = str(request.form.get('num', ''))
+ date_posted = str(request.form.get('date_posted', ''))
+
+ splitvalue1 = int(request.form.get('splitvalue1', ''))
+ splitaccount1 = str(request.form.get('splitaccount1', ''))
+ splitvalue2 = int(request.form.get('splitvalue2', ''))
+ splitaccount2 = str(request.form.get('splitaccount2', ''))
+
+ splits = [
+ {'value': splitvalue1, 'account_guid': splitaccount1},
+ {'value': splitvalue2, 'account_guid': splitaccount2}]
+
+ try:
+ transaction = addTransaction(session.book, num, description,
+ date_posted, currency, splits)
+ except Error as error:
+ return Response(json.dumps({'errors': [{'type' : error.type,
+ 'message': error.message, 'data': error.data}]}), status=400,
+ mimetype='application/json')
+ else:
+ return Response(json.dumps(transaction), status=201,
+ mimetype='application/json')
+
+ else:
+ abort(405)
+
+ at app.route('/transactions/<guid>', methods=['GET', 'POST', 'DELETE'])
+def api_transaction(guid):
+
+ if request.method == 'GET':
+
+ transaction = getTransaction(session.book, guid)
+
+ if transaction is None:
+ abort(404)
+
+ return Response(json.dumps(transaction), mimetype='application/json')
+
+ elif request.method == 'POST':
+
+ currency = str(request.form.get('currency', ''))
+ description = str(request.form.get('description', ''))
+ num = str(request.form.get('num', ''))
+ date_posted = str(request.form.get('date_posted', ''))
+
+ splitguid1 = str(request.form.get('splitguid1', ''))
+ splitvalue1 = int(request.form.get('splitvalue1', ''))
+ splitaccount1 = str(request.form.get('splitaccount1', ''))
+ splitguid2 = str(request.form.get('splitguid2', ''))
+ splitvalue2 = int(request.form.get('splitvalue2', ''))
+ splitaccount2 = str(request.form.get('splitaccount2', ''))
+
+ splits = [
+ {'guid': splitguid1,
+ 'value': splitvalue1,
+ 'account_guid': splitaccount1},
+ {'guid': splitguid2,
+ 'value': splitvalue2,
+ 'account_guid': splitaccount2}
+ ]
+
+ try:
+ transaction = editTransaction(session.book, guid, num, description,
+ date_posted, currency, splits)
+ except Error as error:
+ return Response(json.dumps({'errors': [{'type' : error.type,
+ 'message': error.message, 'data': error.data}]}), status=400, mimetype='application/json')
+ else:
+ return Response(json.dumps(transaction), status=200,
+ mimetype='application/json')
+
+ elif request.method == 'DELETE':
+
+ deleteTransaction(session.book, guid)
+
+ return Response('', status=200, mimetype='application/json')
+
+ else:
+ abort(405)
+
+ at app.route('/bills', methods=['GET', 'POST'])
+def api_bills():
+
+ if request.method == 'GET':
+
+ is_paid = request.args.get('is_paid', None)
+ is_active = request.args.get('is_active', None)
+ date_opened_to = request.args.get('date_opened_to', None)
+ date_opened_from = request.args.get('date_opened_from', None)
+
+ if is_paid == '1':
+ is_paid = 1
+ elif is_paid == '0':
+ is_paid = 0
+ else:
+ is_paid = None
+
+ if is_active == '1':
+ is_active = 1
+ elif is_active == '0':
+ is_active = 0
+ else:
+ is_active = None
+
+ bills = getBills(session.book, None, is_paid, is_active,
+ date_opened_from, date_opened_to)
+
+ return Response(json.dumps(bills), mimetype='application/json')
+
+ elif request.method == 'POST':
+
+ id = str(request.form.get('id', None))
+
+ if id == '':
+ id = None
+ elif id != None:
+ id = str(id)
+
+ vendor_id = str(request.form.get('vendor_id', ''))
+ currency = str(request.form.get('currency', ''))
+ date_opened = str(request.form.get('date_opened', ''))
+ notes = str(request.form.get('notes', ''))
+
+ try:
+ bill = addBill(session.book, id, vendor_id, currency, date_opened,
+ notes)
+ except Error as error:
+ # handle incorrect parameter errors
+ return Response(json.dumps({'errors': [{'type' : error.type,
+ 'message': error.message, 'data': error.data}]}), status=400, mimetype='application/json')
+ else:
+ return Response(json.dumps(bill), status=201,
+ mimetype='application/json')
+
+ else:
+ abort(405)
+
+ at app.route('/bills/<id>', methods=['GET', 'POST', 'PAY'])
+def api_bill(id):
+
+ if request.method == 'GET':
+
+ bill = getBill(session.book, id)
+
+ if bill is None:
+ abort(404)
+ else:
+ return Response(json.dumps(bill), mimetype='application/json')
+
+ elif request.method == 'POST':
+
+ vendor_id = str(request.form.get('vendor_id', ''))
+ currency = str(request.form.get('currency', ''))
+ date_opened = request.form.get('date_opened', None)
+ notes = str(request.form.get('notes', ''))
+ posted = request.form.get('posted', None)
+ posted_account_guid = str(request.form.get('posted_account_guid', ''))
+ posted_date = request.form.get('posted_date', '')
+ due_date = request.form.get('due_date', '')
+ posted_memo = str(request.form.get('posted_memo', ''))
+ posted_accumulatesplits = request.form.get('posted_accumulatesplits',
+ '')
+ posted_autopay = request.form.get('posted_autopay', '')
+
+ if posted == '1':
+ posted = 1
+ else:
+ posted = 0
+
+ if (posted_accumulatesplits == '1'
+ or posted_accumulatesplits == 'true'
+ or posted_accumulatesplits == 'True'
+ or posted_accumulatesplits == True):
+ posted_accumulatesplits = True
+ else:
+ posted_accumulatesplits = False
+
+ if posted_autopay == '1':
+ posted_autopay = True
+ else:
+ posted_autopay = False
+ try:
+ bill = updateBill(session.book, id, vendor_id, currency,
+ date_opened, notes, posted, posted_account_guid, posted_date,
+ due_date, posted_memo, posted_accumulatesplits, posted_autopay)
+ except Error as error:
+ return Response(json.dumps({'errors': [{'type' : error.type,
+ 'message': error.message, 'data': error.data}]}), status=400,
+ mimetype='application/json')
+ else:
+ return Response(json.dumps(bill), status=200,
+ mimetype='application/json')
+
+ if bill is None:
+ abort(404)
+ else:
+ return Response(json.dumps(bill),
+ mimetype='application/json')
+
+ elif request.method == 'PAY':
+
+ posted_account_guid = str(request.form.get('posted_account_guid', ''))
+ transfer_account_guid = str(request.form.get('transfer_account_guid',
+ ''))
+ payment_date = request.form.get('payment_date', '')
+ num = str(request.form.get('num', ''))
+ memo = str(request.form.get('posted_memo', ''))
+ auto_pay = request.form.get('auto_pay', '')
+
+ try:
+ bill = payBill(session.book, id, posted_account_guid,
+ transfer_account_guid, payment_date, memo, num, auto_pay)
+ except Error as error:
+ return Response(json.dumps({'errors': [{'type' : error.type,
+ 'message': error.message, 'data': error.data}]}), status=400,
+ mimetype='application/json')
+ else:
+ return Response(json.dumps(bill), status=200,
+ mimetype='application/json')
+
+ else:
+ abort(405)
+
+ at app.route('/bills/<id>/entries', methods=['GET', 'POST'])
+def api_bill_entries(id):
+
+ bill = getBill(session.book, id)
+
+ if bill is None:
+ abort(404)
+ else:
+ if request.method == 'GET':
+ return Response(json.dumps(bill['entries']), mimetype='application/json')
+ elif request.method == 'POST':
+
+ date = str(request.form.get('date', ''))
+ description = str(request.form.get('description', ''))
+ account_guid = str(request.form.get('account_guid', ''))
+ quantity = str(request.form.get('quantity', ''))
+ price = str(request.form.get('price', ''))
+
+ try:
+ entry = addBillEntry(session.book, id, date, description,
+ account_guid, quantity, price)
+ except Error as error:
+ return Response(json.dumps({'errors': [{'type' : error.type,
+ 'message': error.message, 'data': error.data}]}),
+ status=400, mimetype='application/json')
+ else:
+ return Response(json.dumps(entry), status=201,
+ mimetype='application/json')
+
+ else:
+ abort(405)
+
+ at app.route('/invoices', methods=['GET', 'POST'])
def api_invoices():
- is_paid = request.args.get('is_paid', None)
- is_active = request.args.get('is_active', None)
+ if request.method == 'GET':
+
+ is_paid = request.args.get('is_paid', None)
+ is_active = request.args.get('is_active', None)
+ date_due_to = request.args.get('date_due_to', None)
+ date_due_from = request.args.get('date_due_from', None)
+
+ if is_paid == '1':
+ is_paid = 1
+ elif is_paid == '0':
+ is_paid = 0
+ else:
+ is_paid = None
+
+ if is_active == '1':
+ is_active = 1
+ elif is_active == '0':
+ is_active = 0
+ else:
+ is_active = None
+
+ invoices = getInvoices(session.book, None, is_paid, is_active,
+ date_due_from, date_due_to)
+
+ return Response(json.dumps(invoices), mimetype='application/json')
+
+ elif request.method == 'POST':
+
+ id = str(request.form.get('id', None))
+
+ if id == '':
+ id = None
+ elif id != None:
+ id = str(id)
+
+ customer_id = str(request.form.get('customer_id', ''))
+ currency = str(request.form.get('currency', ''))
+ date_opened = str(request.form.get('date_opened', ''))
+ notes = str(request.form.get('notes', ''))
+
+ try:
+ invoice = addInvoice(session.book, id, customer_id, currency,
+ date_opened, notes)
+ except Error as error:
+ return Response(json.dumps({'errors': [{'type' : error.type,
+ 'message': error.message, 'data': error.data}]}), status=400,
+ mimetype='application/json')
+ else:
+ return Response(json.dumps(invoice), status=201,
+ mimetype='application/json')
+
+ else:
+ abort(405)
+
+ at app.route('/invoices/<id>', methods=['GET', 'POST', 'PAY'])
+def api_invoice(id):
- if is_paid == '1':
- is_paid = 1
- elif is_paid == '0':
- is_paid = 0
- else:
- is_paid = None
+ if request.method == 'GET':
+
+ invoice = getInvoice(session.book, id)
+
+ if invoice is None:
+ abort(404)
+ else:
+ return Response(json.dumps(invoice), mimetype='application/json')
+
+ elif request.method == 'POST':
+
+ customer_id = str(request.form.get('customer_id', ''))
+ currency = str(request.form.get('currency', ''))
+ date_opened = request.form.get('date_opened', None)
+ notes = str(request.form.get('notes', ''))
+ posted = request.form.get('posted', None)
+ posted_account_guid = str(request.form.get('posted_account_guid', ''))
+ posted_date = request.form.get('posted_date', '')
+ due_date = request.form.get('due_date', '')
+ posted_memo = str(request.form.get('posted_memo', ''))
+ posted_accumulatesplits = request.form.get('posted_accumulatesplits',
+ '')
+ posted_autopay = request.form.get('posted_autopay', '')
+
+ if posted == '1':
+ posted = 1
+ else:
+ posted = 0
+
+ if (posted_accumulatesplits == '1'
+ or posted_accumulatesplits == 'true'
+ or posted_accumulatesplits == 'True'
+ or posted_accumulatesplits == True):
+ posted_accumulatesplits = True
+ else:
+ posted_accumulatesplits = False
+
+ if posted_autopay == '1':
+ posted_autopay = True
+ else:
+ posted_autopay = False
+ try:
+ invoice = updateInvoice(session.book, id, customer_id, currency,
+ date_opened, notes, posted, posted_account_guid, posted_date,
+ due_date, posted_memo, posted_accumulatesplits, posted_autopay)
+ except Error as error:
+ return Response(json.dumps({'errors': [{'type' : error.type,
+ 'message': error.message, 'data': error.data}]}), status=400,
+ mimetype='application/json')
+ else:
+ return Response(json.dumps(invoice), status=200,
+ mimetype='application/json')
+
+ if invoice is None:
+ abort(404)
+ else:
+ return Response(json.dumps(invoice), mimetype='application/json')
+
+ elif request.method == 'PAY':
+
+ posted_account_guid = str(request.form.get('posted_account_guid', ''))
+ transfer_account_guid = str(request.form.get('transfer_account_guid',
+ ''))
+ payment_date = request.form.get('payment_date', '')
+ num = str(request.form.get('num', ''))
+ memo = str(request.form.get('posted_memo', ''))
+ auto_pay = request.form.get('auto_pay', '')
+
+ try:
+ invoice = payInvoice(session.book, id, posted_account_guid,
+ transfer_account_guid, payment_date, memo, num, auto_pay)
+ except Error as error:
+ return Response(json.dumps({'errors': [{'type' : error.type,
+ 'message': error.message, 'data': error.data}]}), status=400,
+ mimetype='application/json')
+ else:
+ return Response(json.dumps(invoice), status=200,
+ mimetype='application/json')
+
+ else:
+ abort(405)
+
+ at app.route('/invoices/<id>/entries', methods=['GET', 'POST'])
+def api_invoice_entries(id):
+
+ invoice = getInvoice(session.book, id)
+
+ if invoice is None:
+ abort(404)
+ else:
+ if request.method == 'GET':
+ return Response(json.dumps(invoice['entries']),
+ mimetype='application/json')
+ elif request.method == 'POST':
+
+ date = str(request.form.get('date', ''))
+ description = str(request.form.get('description', ''))
+ account_guid = str(request.form.get('account_guid', ''))
+ quantity = str(request.form.get('quantity', ''))
+ price = str(request.form.get('price', ''))
+
+ try:
+ entry = addEntry(session.book, id, date, description,
+ account_guid, quantity, price)
+ except Error as error:
+ return Response(json.dumps({'errors': [{'type' : error.type,
+ 'message': error.message, 'data': error.data}]}),
+ status=400, mimetype='application/json')
+ else:
+ return Response(json.dumps(entry), status=201,
+ mimetype='application/json')
+
+ else:
+ abort(405)
+
+ at app.route('/entries/<guid>', methods=['GET', 'POST', 'DELETE'])
+def api_entry(guid):
+
+ entry = getEntry(session.book, guid)
+
+ if entry is None:
+ abort(404)
+ else:
+ if request.method == 'GET':
+ return Response(json.dumps(entry), mimetype='application/json')
+ elif request.method == 'POST':
+
+ date = str(request.form.get('date', ''))
+ description = str(request.form.get('description', ''))
+ account_guid = str(request.form.get('account_guid', ''))
+ quantity = str(request.form.get('quantity', ''))
+ price = str(request.form.get('price', ''))
+
+ try:
+ entry = updateEntry(session.book, guid, date, description,
+ account_guid, quantity, price)
+ except Error as error:
+ return Response(json.dumps({'errors': [{'type' : error.type,
+ 'message': error.message, 'data': error.data}]}),
+ status=400, mimetype='application/json')
+ else:
+ return Response(json.dumps(entry), status=200,
+ mimetype='application/json')
+
+ elif request.method == 'DELETE':
+
+ deleteEntry(session.book, guid)
+
+ return Response('', status=201, mimetype='application/json')
+
+ else:
+ abort(405)
+
+ at app.route('/customers', methods=['GET', 'POST'])
+def api_customers():
+
+ if request.method == 'GET':
+ customers = getCustomers(session.book)
+ return Response(json.dumps(customers), mimetype='application/json')
+ elif request.method == 'POST':
+
+ id = str(request.form.get('id', None))
+
+ if id == '':
+ id = None
+ elif id != None:
+ id = str(id)
+
+ currency = str(request.form.get('currency', ''))
+ name = str(request.form.get('name', ''))
+ contact = str(request.form.get('contact', ''))
+ address_line_1 = str(request.form.get('address_line_1', ''))
+ address_line_2 = str(request.form.get('address_line_2', ''))
+ address_line_3 = str(request.form.get('address_line_3', ''))
+ address_line_4 = str(request.form.get('address_line_4', ''))
+ phone = str(request.form.get('phone', ''))
+ fax = str(request.form.get('fax', ''))
+ email = str(request.form.get('email', ''))
+
+ try:
+ customer = addCustomer(session.book, id, currency, name, contact,
+ address_line_1, address_line_2, address_line_3, address_line_4,
+ phone, fax, email)
+ except Error as error:
+ return Response(json.dumps({'errors': [{'type' : error.type,
+ 'message': error.message, 'data': error.data}]}), status=400,
+ mimetype='application/json')
+ else:
+ return Response(json.dumps(customer), status=201,
+ mimetype='application/json')
+
+ else:
+ abort(405)
+
+ at app.route('/customers/<id>', methods=['GET', 'POST'])
+def api_customer(id):
- if is_active == '1':
- is_active = 1
- elif is_active == '0':
- is_active = 0
- else:
- is_active = None
+ if request.method == 'GET':
+
+ customer = getCustomer(session.book, id)
+
+ if customer is None:
+ abort(404)
+ else:
+ return Response(json.dumps(customer), mimetype='application/json')
+
+ elif request.method == 'POST':
+
+ id = str(request.form.get('id', None))
+
+ name = str(request.form.get('name', ''))
+ contact = str(request.form.get('contact', ''))
+ address_line_1 = str(request.form.get('address_line_1', ''))
+ address_line_2 = str(request.form.get('address_line_2', ''))
+ address_line_3 = str(request.form.get('address_line_3', ''))
+ address_line_4 = str(request.form.get('address_line_4', ''))
+ phone = str(request.form.get('phone', ''))
+ fax = str(request.form.get('fax', ''))
+ email = str(request.form.get('email', ''))
+
+ try:
+ customer = updateCustomer(session.book, id, name, contact,
+ address_line_1, address_line_2, address_line_3, address_line_4,
+ phone, fax, email)
+ except Error as error:
+ if error.type == 'NoCustomer':
+ return Response(json.dumps({'errors': [{'type' : error.type,
+ 'message': error.message, 'data': error.data}]}),
+ status=404, mimetype='application/json')
+ else:
+ return Response(json.dumps({'errors': [{'type' : error.type,
+ 'message': error.message, 'data': error.data}]}),
+ status=400, mimetype='application/json')
+ else:
+ return Response(json.dumps(customer), status=200,
+ mimetype='application/json')
+
+ else:
+ abort(405)
+
+ at app.route('/customers/<id>/invoices', methods=['GET'])
+def api_customer_invoices(id):
+
+ customer = getCustomer(session.book, id)
+
+ if customer is None:
+ abort(404)
+
+ invoices = getInvoices(session.book, customer['guid'], None, None, None,
+ None)
+
+ return Response(json.dumps(invoices), mimetype='application/json')
+
+ at app.route('/vendors', methods=['GET', 'POST'])
+def api_vendors():
+
+ if request.method == 'GET':
+ vendors = getVendors(session.book)
+ return Response(json.dumps(vendors), mimetype='application/json')
+ elif request.method == 'POST':
+
+ id = str(request.form.get('id', None))
+
+ if id == '':
+ id = None
+ elif id != None:
+ id = str(id)
+
+ currency = str(request.form.get('currency', ''))
+ name = str(request.form.get('name', ''))
+ contact = str(request.form.get('contact', ''))
+ address_line_1 = str(request.form.get('address_line_1', ''))
+ address_line_2 = str(request.form.get('address_line_2', ''))
+ address_line_3 = str(request.form.get('address_line_3', ''))
+ address_line_4 = str(request.form.get('address_line_4', ''))
+ phone = str(request.form.get('phone', ''))
+ fax = str(request.form.get('fax', ''))
+ email = str(request.form.get('email', ''))
+
+ try:
+ vendor = addVendor(session.book, id, currency, name, contact,
+ address_line_1, address_line_2, address_line_3, address_line_4,
+ phone, fax, email)
+ except Error as error:
+ return Response(json.dumps({'errors': [{'type' : error.type,
+ 'message': error.message, 'data': error.data}]}), status=400,
+ mimetype='application/json')
+ else:
+ return Response(json.dumps(vendor), status=201,
+ mimetype='application/json')
+
+ else:
+ abort(405)
+
+ at app.route('/vendors/<id>', methods=['GET', 'POST'])
+def api_vendor(id):
+
+ if request.method == 'GET':
+
+ vendor = getVendor(session.book, id)
+
+ if vendor is None:
+ abort(404)
+ else:
+ return Response(json.dumps(vendor), mimetype='application/json')
+ else:
+ abort(405)
+
+ at app.route('/vendors/<id>/bills', methods=['GET'])
+def api_vendor_bills(id):
+
+ vendor = getVendor(session.book, id)
+
+ if vendor is None:
+ abort(404)
+
+ bills = getBills(session.book, vendor['guid'], None, None, None, None)
+
+ return Response(json.dumps(bills), mimetype='application/json')
- invoices = getInvoices(session.book, is_paid, is_active)
+def getCustomers(book):
- return invoices
+ query = gnucash.Query()
+ query.search_for('gncCustomer')
+ query.set_book(book)
+ customers = []
- at app.route('/invoices/<id>')
-def api_invoice(id):
+ for result in query.run():
+ customers.append(gnucash_simple.customerToDict(
+ gnucash.gnucash_business.Customer(instance=result)))
- invoice = getInvoice(session.book, id)
+ query.destroy()
- if invoice is None:
- abort(404)
- else:
- return invoice
+ return customers
+def getCustomer(book, id):
- at app.route('/customers')
-def api_customers():
+ customer = book.CustomerLookupByID(id)
- customers = getCustomers(session.book)
+ if customer is None:
+ return None
+ else:
+ return gnucash_simple.customerToDict(customer)
- return customers
+def getVendors(book):
- at app.route('/customers/<id>')
-def api_customer(id):
+ query = gnucash.Query()
+ query.search_for('gncVendor')
+ query.set_book(book)
+ vendors = []
- customer = getCustomer(session.book, id)
+ for result in query.run():
+ vendors.append(gnucash_simple.vendorToDict(
+ gnucash.gnucash_business.Vendor(instance=result)))
- if customer is None:
- abort(404)
- else:
- return customer
+ query.destroy()
-def getCustomers(book):
+ return vendors
- query = gnucash.Query()
- query.search_for('gncCustomer')
- query.set_book(book)
- customers = []
+def getVendor(book, id):
- for result in query.run():
- customers.append(gnucash_simple.customerToDict(gnucash.gnucash_business.Customer(instance=result)))
+ vendor = book.VendorLookupByID(id)
- query.destroy()
+ if vendor is None:
+ return None
+ else:
+ return gnucash_simple.vendorToDict(vendor)
- return json.dumps(customers)
+def getAccounts(book):
-def getCustomer(book, id):
+ accounts = gnucash_simple.accountToDict(book.get_root_account())
- customer = book.CustomerLookupByID(id)
+ return accounts
- if customer is None:
- return None
- else:
- return json.dumps(gnucash_simple.customerToDict(customer))
+def getAccountsFlat(book):
-def getAccounts(book):
+ accounts = gnucash_simple.accountToDict(book.get_root_account())
+
+ flat_accounts = getSubAccounts(accounts)
+
+ for n, account in enumerate(flat_accounts):
+ account.pop('subaccounts')
+
+ filtered_flat_account = []
- accounts = gnucash_simple.accountToDict(book.get_root_account())
+ type_ids = [9]
- return json.dumps(accounts)
+ for n, account in enumerate(flat_accounts):
+ if account['type_id'] in type_ids:
+ filtered_flat_account.append(account)
+ print account['name'] + ' ' + str(account['type_id'])
+
+ return filtered_flat_account
+
+def getSubAccounts(account):
+
+ flat_accounts = []
+
+ if 'subaccounts' in account.keys():
+ for n, subaccount in enumerate(account['subaccounts']):
+ flat_accounts.append(subaccount)
+ flat_accounts = flat_accounts + getSubAccounts(subaccount)
+
+ return flat_accounts
def getAccount(book, guid):
- account_guid = gnucash.gnucash_core.GUID()
- gnucash.gnucash_core.GUIDString(guid, account_guid)
+ account_guid = gnucash.gnucash_core.GUID()
+ gnucash.gnucash_core.GUIDString(guid, account_guid)
+
+ account = account_guid.AccountLookup(book)
+
+ if account is None:
+ return None
+
+ account = gnucash_simple.accountToDict(account)
+
+ if account is None:
+ return None
+ else:
+ return account
+
+
+def getTransaction(book, guid):
+
+ transaction_guid = gnucash.gnucash_core.GUID()
+ gnucash.gnucash_core.GUIDString(guid, transaction_guid)
+
+ transaction = transaction_guid.TransactionLookup(book)
+
+ if transaction is None:
+ return None
+
+ transaction = gnucash_simple.transactionToDict(transaction, ['splits'])
+
+ if transaction is None:
+ return None
+ else:
+ return transaction
+
+def getTransactions(book, account_guid, date_posted_from, date_posted_to):
+
+ query = gnucash.Query()
+
+ query.search_for('Trans')
+ query.set_book(book)
+
+ transactions = []
+
+ for transaction in query.run():
+ transactions.append(gnucash_simple.transactionToDict(
+ gnucash.gnucash_business.Transaction(instance=transaction)))
+
+ query.destroy()
+
+ return transactions
+
+def getAccountSplits(book, guid, date_posted_from, date_posted_to):
+
+ account_guid = gnucash.gnucash_core.GUID()
+ gnucash.gnucash_core.GUIDString(guid, account_guid)
+
+ query = gnucash.Query()
+ query.search_for('Split')
+ query.set_book(book)
+
+ SPLIT_TRANS= 'trans'
+
+ QOF_DATE_MATCH_NORMAL = 1
+
+ TRANS_DATE_POSTED = 'date-posted'
- account = gnucash_simple.accountToDict(account_guid.AccountLookup(book))
+ if date_posted_from != None:
+ pred_data = gnucash.gnucash_core.QueryDatePredicate(
+ QOF_COMPARE_GTE, QOF_DATE_MATCH_NORMAL, datetime.datetime.strptime(
+ date_posted_from, "%Y-%m-%d").date())
+ param_list = [SPLIT_TRANS, TRANS_DATE_POSTED]
+ query.add_term(param_list, pred_data, QOF_QUERY_AND)
- if account is None:
- return None
- else:
- return json.dumps(account)
+ if date_posted_to != None:
+ pred_data = gnucash.gnucash_core.QueryDatePredicate(
+ QOF_COMPARE_LTE, QOF_DATE_MATCH_NORMAL, datetime.datetime.strptime(
+ date_posted_to, "%Y-%m-%d").date())
+ param_list = [SPLIT_TRANS, TRANS_DATE_POSTED]
+ query.add_term(param_list, pred_data, QOF_QUERY_AND)
+
+ SPLIT_ACCOUNT = 'account'
+ QOF_PARAM_GUID = 'guid'
+ if guid != None:
+ gnucash.gnucash_core.GUIDString(guid, account_guid)
+ query.add_guid_match(
+ [SPLIT_ACCOUNT, QOF_PARAM_GUID], account_guid, QOF_QUERY_AND)
-def getInvoices(book, is_paid, is_active):
+ splits = []
- query = gnucash.Query()
- query.search_for('gncInvoice')
- query.set_book(book)
+ for split in query.run():
+ splits.append(gnucash_simple.splitToDict(
+ gnucash.gnucash_business.Split(instance=split),
+ ['account', 'transaction', 'other_split']))
- if is_paid == 0:
- query.add_boolean_match([INVOICE_IS_PAID], False, QOF_QUERY_AND)
- elif is_paid == 1:
- query.add_boolean_match([INVOICE_IS_PAID], True, QOF_QUERY_AND)
+ query.destroy()
- # active = JOB_IS_ACTIVE
- if is_active == 0:
- query.add_boolean_match(['active'], False, QOF_QUERY_AND)
- elif is_active == 1:
- query.add_boolean_match(['active'], True, QOF_QUERY_AND)
+ return splits
- # return only invoices (1 = invoices)
- pred_data = gnucash.gnucash_core.QueryInt32Predicate(QOF_COMPARE_EQUAL, 1)
- query.add_term([INVOICE_TYPE], pred_data, QOF_QUERY_AND)
+def getInvoices(book, customer, is_paid, is_active, date_due_from,
+ date_due_to):
- invoices = []
+ query = gnucash.Query()
+ query.search_for('gncInvoice')
+ query.set_book(book)
- for result in query.run():
- invoices.append(gnucash_simple.invoiceToDict(gnucash.gnucash_business.Invoice(instance=result)))
+ if is_paid == 0:
+ query.add_boolean_match([INVOICE_IS_PAID], False, QOF_QUERY_AND)
+ elif is_paid == 1:
+ query.add_boolean_match([INVOICE_IS_PAID], True, QOF_QUERY_AND)
- query.destroy()
+ # active = JOB_IS_ACTIVE
+ if is_active == 0:
+ query.add_boolean_match(['active'], False, QOF_QUERY_AND)
+ elif is_active == 1:
+ query.add_boolean_match(['active'], True, QOF_QUERY_AND)
- return json.dumps(invoices)
+ QOF_PARAM_GUID = 'guid'
+ INVOICE_OWNER = 'owner'
+
+ if customer != None:
+ customer_guid = gnucash.gnucash_core.GUID()
+ gnucash.gnucash_core.GUIDString(customer, customer_guid)
+ query.add_guid_match(
+ [INVOICE_OWNER, QOF_PARAM_GUID], customer_guid, QOF_QUERY_AND)
+
+ if date_due_from != None:
+ pred_data = gnucash.gnucash_core.QueryDatePredicate(
+ QOF_COMPARE_GTE, 2, datetime.datetime.strptime(
+ date_due_from, "%Y-%m-%d").date())
+ query.add_term(['date_due'], pred_data, QOF_QUERY_AND)
+
+ if date_due_to != None:
+ pred_data = gnucash.gnucash_core.QueryDatePredicate(
+ QOF_COMPARE_LTE, 2, datetime.datetime.strptime(
+ date_due_to, "%Y-%m-%d").date())
+ query.add_term(['date_due'], pred_data, QOF_QUERY_AND)
+
+ # return only invoices (1 = invoices)
+ pred_data = gnucash.gnucash_core.QueryInt32Predicate(QOF_COMPARE_EQUAL, 1)
+ query.add_term([INVOICE_TYPE], pred_data, QOF_QUERY_AND)
+
+ invoices = []
+
+ for result in query.run():
+ invoices.append(gnucash_simple.invoiceToDict(
+ gnucash.gnucash_business.Invoice(instance=result)))
+
+ query.destroy()
+
+ return invoices
+
+def getBills(book, customer, is_paid, is_active, date_opened_from,
+ date_opened_to):
+
+ query = gnucash.Query()
+ query.search_for('gncInvoice')
+ query.set_book(book)
+
+ if is_paid == 0:
+ query.add_boolean_match([INVOICE_IS_PAID], False, QOF_QUERY_AND)
+ elif is_paid == 1:
+ query.add_boolean_match([INVOICE_IS_PAID], True, QOF_QUERY_AND)
+
+ # active = JOB_IS_ACTIVE
+ if is_active == 0:
+ query.add_boolean_match(['active'], False, QOF_QUERY_AND)
+ elif is_active == 1:
+ query.add_boolean_match(['active'], True, QOF_QUERY_AND)
+
+ QOF_PARAM_GUID = 'guid'
+ INVOICE_OWNER = 'owner'
+
+ if customer != None:
+ customer_guid = gnucash.gnucash_core.GUID()
+ gnucash.gnucash_core.GUIDString(customer, customer_guid)
+ query.add_guid_match(
+ [INVOICE_OWNER, QOF_PARAM_GUID], customer_guid, QOF_QUERY_AND)
+
+ if date_opened_from != None:
+ pred_data = gnucash.gnucash_core.QueryDatePredicate(
+ QOF_COMPARE_GTE, 2, datetime.datetime.strptime(
+ date_opened_from, "%Y-%m-%d").date())
+ query.add_term(['date_opened'], pred_data, QOF_QUERY_AND)
+
+ if date_opened_to != None:
+ pred_data = gnucash.gnucash_core.QueryDatePredicate(
+ QOF_COMPARE_LTE, 2, datetime.datetime.strptime(
+ date_opened_to, "%Y-%m-%d").date())
+ query.add_term(['date_opened'], pred_data, QOF_QUERY_AND)
+
+ # return only bills (2 = bills)
+ pred_data = gnucash.gnucash_core.QueryInt32Predicate(QOF_COMPARE_EQUAL, 2)
+ query.add_term([INVOICE_TYPE], pred_data, QOF_QUERY_AND)
+
+ bills = []
+
+ for result in query.run():
+ bills.append(gnucash_simple.billToDict(
+ gnucash.gnucash_business.Bill(instance=result)))
+
+ query.destroy()
+
+ return bills
+
+def getGnuCashInvoice(book ,id):
+
+ # we don't use book.InvoicelLookupByID(id) as this is identical to
+ # book.BillLookupByID(id) so can return the same object if they share IDs
+
+ query = gnucash.Query()
+ query.search_for('gncInvoice')
+ query.set_book(book)
+
+ # return only invoices (1 = invoices)
+ pred_data = gnucash.gnucash_core.QueryInt32Predicate(QOF_COMPARE_EQUAL, 1)
+ query.add_term([INVOICE_TYPE], pred_data, QOF_QUERY_AND)
+
+ INVOICE_ID = 'id'
+
+ pred_data = gnucash.gnucash_core.QueryStringPredicate(
+ QOF_COMPARE_EQUAL, id, QOF_STRING_MATCH_NORMAL, False)
+ query.add_term([INVOICE_ID], pred_data, QOF_QUERY_AND)
+
+ invoice = None
+
+ for result in query.run():
+ invoice = gnucash.gnucash_business.Invoice(instance=result)
+
+ query.destroy()
+
+ return invoice
+
+def getGnuCashBill(book ,id):
+
+ # we don't use book.InvoicelLookupByID(id) as this is identical to
+ # book.BillLookupByID(id) so can return the same object if they share IDs
+
+ query = gnucash.Query()
+ query.search_for('gncInvoice')
+ query.set_book(book)
+
+ # return only bills (2 = bills)
+ pred_data = gnucash.gnucash_core.QueryInt32Predicate(QOF_COMPARE_EQUAL, 2)
+ query.add_term([INVOICE_TYPE], pred_data, QOF_QUERY_AND)
+
+ INVOICE_ID = 'id'
+
+ pred_data = gnucash.gnucash_core.QueryStringPredicate(
+ QOF_COMPARE_EQUAL, id, QOF_STRING_MATCH_NORMAL, False)
+ query.add_term([INVOICE_ID], pred_data, QOF_QUERY_AND)
+
+ bill = None
+
+ for result in query.run():
+ bill = gnucash.gnucash_business.Bill(instance=result)
+
+ query.destroy()
+
+ return bill
def getInvoice(book, id):
- invoice = book.InvoiceLookupByID(id)
+ return gnucash_simple.invoiceToDict(getGnuCashInvoice(book, id))
+
+def payInvoice(book, id, posted_account_guid, transfer_account_guid,
+ payment_date, memo, num, auto_pay):
+
+ invoice = getGnuCashInvoice(book, id)
+
+ account_guid2 = gnucash.gnucash_core.GUID()
+ gnucash.gnucash_core.GUIDString(transfer_account_guid, account_guid2)
+
+ xfer_acc = account_guid2.AccountLookup(session.book)
+
+ invoice.ApplyPayment(None, xfer_acc, invoice.GetTotal(), GncNumeric(0),
+ datetime.datetime.strptime(payment_date, '%Y-%m-%d'), memo, num)
+
+ return gnucash_simple.invoiceToDict(invoice)
+
+def payBill(book, id, posted_account_guid, transfer_account_guid, payment_date,
+ memo, num, auto_pay):
+
+ bill = getGnuCashBill(book, id)
+
+ account_guid = gnucash.gnucash_core.GUID()
+ gnucash.gnucash_core.GUIDString(transfer_account_guid, account_guid)
+
+ xfer_acc = account_guid.AccountLookup(session.book)
+
+ # We pay the negitive total as the bill as this seemed to cause issues
+ # with the split not being set correctly and not being marked as paid
+ bill.ApplyPayment(None, xfer_acc, bill.GetTotal().neg(), GncNumeric(0),
+ datetime.datetime.strptime(payment_date, '%Y-%m-%d'), memo, num)
+
+ return gnucash_simple.billToDict(bill)
+
+def getBill(book, id):
+
+ return gnucash_simple.billToDict(getGnuCashBill(book, id))
+
+def addVendor(book, id, currency_mnumonic, name, contact, address_line_1,
+ address_line_2, address_line_3, address_line_4, phone, fax, email):
+
+ if name == '':
+ raise Error('NoVendorName', 'A name must be entered for this company',
+ {'field': 'name'})
+
+ if (address_line_1 == ''
+ and address_line_2 == ''
+ and address_line_3 == ''
+ and address_line_4 == ''):
+ raise Error('NoVendorAddress',
+ 'An address must be entered for this company',
+ {'field': 'address'})
- if invoice is None:
- return None
- else:
- #print invoiceToDict(invoice)
- return json.dumps(gnucash_simple.invoiceToDict(invoice))
+ commod_table = book.get_table()
+ currency = commod_table.lookup('CURRENCY', currency_mnumonic)
+
+ if currency is None:
+ raise Error('InvalidVendorCurrency',
+ 'A valid currency must be supplied for this vendor',
+ {'field': 'currency'})
+
+ if id is None:
+ id = book.VendorNextID()
+
+ vendor = Vendor(session.book, id, currency, name)
+
+ address = vendor.GetAddr()
+ address.SetName(contact)
+ address.SetAddr1(address_line_1)
+ address.SetAddr2(address_line_2)
+ address.SetAddr3(address_line_3)
+ address.SetAddr4(address_line_4)
+ address.SetPhone(phone)
+ address.SetFax(fax)
+ address.SetEmail(email)
+
+ return gnucash_simple.vendorToDict(vendor)
+
+def addCustomer(book, id, currency_mnumonic, name, contact, address_line_1,
+ address_line_2, address_line_3, address_line_4, phone, fax, email):
+
+ if name == '':
+ raise Error('NoCustomerName',
+ 'A name must be entered for this company', {'field': 'name'})
+
+ if (address_line_1 == ''
+ and address_line_2 == ''
+ and address_line_3 == ''
+ and address_line_4 == ''):
+ raise Error('NoCustomerAddress',
+ 'An address must be entered for this company',
+ {'field': 'address'})
+
+ commod_table = book.get_table()
+ currency = commod_table.lookup('CURRENCY', currency_mnumonic)
+
+ if currency is None:
+ raise Error('InvalidCustomerCurrency',
+ 'A valid currency must be supplied for this customer',
+ {'field': 'currency'})
+
+ if id is None:
+ id = book.CustomerNextID()
+
+ customer = Customer(session.book, id, currency, name)
+
+ address = customer.GetAddr()
+ address.SetName(contact)
+ address.SetAddr1(address_line_1)
+ address.SetAddr2(address_line_2)
+ address.SetAddr3(address_line_3)
+ address.SetAddr4(address_line_4)
+ address.SetPhone(phone)
+ address.SetFax(fax)
+ address.SetEmail(email)
+
+ return gnucash_simple.customerToDict(customer)
+
+def updateCustomer(book, id, name, contact, address_line_1, address_line_2,
+ address_line_3, address_line_4, phone, fax, email):
+
+ customer = book.CustomerLookupByID(id)
+
+ if customer is None:
+ raise Error('NoCustomer', 'A customer with this ID does not exist',
+ {'field': 'id'})
+
+ if name == '':
+ raise Error('NoCustomerName',
+ 'A name must be entered for this company', {'field': 'name'})
+
+ if (address_line_1 == ''
+ and address_line_2 == ''
+ and address_line_3 == ''
+ and address_line_4 == ''):
+ raise Error('NoCustomerAddress',
+ 'An address must be entered for this company',
+ {'field': 'address'})
+
+ customer.SetName(name)
+
+ address = customer.GetAddr()
+ address.SetName(contact)
+ address.SetAddr1(address_line_1)
+ address.SetAddr2(address_line_2)
+ address.SetAddr3(address_line_3)
+ address.SetAddr4(address_line_4)
+ address.SetPhone(phone)
+ address.SetFax(fax)
+ address.SetEmail(email)
+
+ return gnucash_simple.customerToDict(customer)
+
+def addInvoice(book, id, customer_id, currency_mnumonic, date_opened, notes):
+
+ customer = book.CustomerLookupByID(customer_id)
+
+ if customer is None:
+ raise Error('NoCustomer',
+ 'A customer with this ID does not exist', {'field': 'id'})
+
+ if id is None:
+ id = book.InvoiceNextID(customer)
+
+ try:
+ date_opened = datetime.datetime.strptime(date_opened, "%Y-%m-%d")
+ except ValueError:
+ raise Error('InvalidDateOpened',
+ 'The date opened must be provided in the form YYYY-MM-DD',
+ {'field': 'date_opened'})
+
+ if currency_mnumonic is None:
+ currency_mnumonic = customer.GetCurrency().get_mnemonic()
+
+ commod_table = book.get_table()
+ currency = commod_table.lookup('CURRENCY', currency_mnumonic)
+
+ if currency is None:
+ raise Error('InvalidCustomerCurrency',
+ 'A valid currency must be supplied for this customer',
+ {'field': 'currency'})
+
+ invoice = Invoice(book, id, currency, customer, date_opened.date())
+
+ invoice.SetNotes(notes)
+
+ return gnucash_simple.invoiceToDict(invoice)
+
+def updateInvoice(book, id, customer_id, currency_mnumonic, date_opened,
+ notes, posted, posted_account_guid, posted_date, due_date, posted_memo,
+ posted_accumulatesplits, posted_autopay):
+
+ invoice = getGnuCashInvoice(book, id)
+
+ if invoice is None:
+ raise Error('NoInvoice',
+ 'An invoice with this ID does not exist',
+ {'field': 'id'})
+
+ customer = book.CustomerLookupByID(customer_id)
+
+ if customer is None:
+ raise Error('NoCustomer', 'A customer with this ID does not exist',
+ {'field': 'customer_id'})
+
+ try:
+ date_opened = datetime.datetime.strptime(date_opened, "%Y-%m-%d")
+ except ValueError:
+ raise Error('InvalidDateOpened',
+ 'The date opened must be provided in the form YYYY-MM-DD',
+ {'field': 'date_opened'})
+
+ if posted_date == '':
+ if posted == 1:
+ raise Error('NoDatePosted',
+ 'The date posted must be supplied when posted=1',
+ {'field': 'date_posted'})
+ else:
+ try:
+ posted_date = datetime.datetime.strptime(posted_date, "%Y-%m-%d")
+ except ValueError:
+ raise Error('InvalidDatePosted',
+ 'The date posted must be provided in the form YYYY-MM-DD',
+ {'field': 'posted_date'})
+
+ if due_date == '':
+ if posted == 1:
+ raise Error('NoDatePosted',
+ 'The due date must be supplied when posted=1',
+ {'field': 'date_posted'})
+ else:
+ try:
+ due_date = datetime.datetime.strptime(due_date, "%Y-%m-%d")
+ except ValueError:
+ raise Error('InvalidDatePosted',
+ 'The due date must be provided in the form YYYY-MM-DD',
+ {'field': 'due_date'})
+
+ if posted_account_guid == '':
+ if posted == 1:
+ raise Error('NoPostedAccountGuid',
+ 'The posted account GUID must be supplied when posted=1',
+ {'field': 'posted_account_guid'})
+ else:
+ guid = gnucash.gnucash_core.GUID()
+ gnucash.gnucash_core.GUIDString(posted_account_guid, guid)
+
+ posted_account = guid.AccountLookup(book)
+
+ if posted_account is None:
+ raise Error('NoAccount',
+ 'No account exists with the posted account GUID',
+ {'field': 'posted_account_guid'})
+
+ invoice.SetOwner(customer)
+ invoice.SetDateOpened(date_opened)
+ invoice.SetNotes(notes)
+
+ # post if currently unposted and posted=1
+ if (invoice.GetDatePosted().strftime('%Y-%m-%d') == '1970-01-01'
+ and posted == 1):
+ invoice.PostToAccount(posted_account, posted_date, due_date,
+ posted_memo, posted_accumulatesplits, posted_autopay)
+
+ return gnucash_simple.invoiceToDict(invoice)
+
+def updateBill(book, id, vendor_id, currency_mnumonic, date_opened, notes,
+ posted, posted_account_guid, posted_date, due_date, posted_memo,
+ posted_accumulatesplits, posted_autopay):
+
+ bill = getGnuCashBill(book, id)
+
+ if bill is None:
+ raise Error('NoBill', 'A bill with this ID does not exist',
+ {'field': 'id'})
+
+ vendor = book.VendorLookupByID(vendor_id)
+
+ if vendor is None:
+ raise Error('NoVendor',
+ 'A vendor with this ID does not exist',
+ {'field': 'vendor_id'})
+
+ try:
+ date_opened = datetime.datetime.strptime(date_opened, "%Y-%m-%d")
+ except ValueError:
+ raise Error('InvalidDateOpened',
+ 'The date opened must be provided in the form YYYY-MM-DD',
+ {'field': 'date_opened'})
+
+ if posted_date == '':
+ if posted == 1:
+ raise Error('NoDatePosted',
+ 'The date posted must be supplied when posted=1',
+ {'field': 'date_posted'})
+ else:
+ try:
+ posted_date = datetime.datetime.strptime(posted_date, "%Y-%m-%d")
+ except ValueError:
+ raise Error('InvalidDatePosted',
+ 'The date posted must be provided in the form YYYY-MM-DD',
+ {'field': 'posted_date'})
+
+ if due_date == '':
+ if posted == 1:
+ raise Error('NoDatePosted',
+ 'The due date must be supplied when posted=1',
+ {'field': 'date_posted'})
+ else:
+ try:
+ due_date = datetime.datetime.strptime(due_date, "%Y-%m-%d")
+ except ValueError:
+ raise Error('InvalidDatePosted',
+ 'The due date must be provided in the form YYYY-MM-DD',
+ {'field': 'due_date'})
+
+ if posted_account_guid == '':
+ if posted == 1:
+ raise Error('NoPostedAccountGuid',
+ 'The posted account GUID must be supplied when posted=1',
+ {'field': 'posted_account_guid'})
+ else:
+ guid = gnucash.gnucash_core.GUID()
+ gnucash.gnucash_core.GUIDString(posted_account_guid, guid)
+
+ posted_account = guid.AccountLookup(book)
+
+ if posted_account is None:
+ raise Error('NoAccount',
+ 'No account exists with the posted account GUID',
+ {'field': 'posted_account_guid'})
+
+ bill.SetOwner(vendor)
+ bill.SetDateOpened(date_opened)
+ bill.SetNotes(notes)
+
+ # post if currently unposted and posted=1
+ if bill.GetDatePosted().strftime('%Y-%m-%d') == '1970-01-01' and posted == 1:
+ bill.PostToAccount(posted_account, posted_date, due_date, posted_memo,
+ posted_accumulatesplits, posted_autopay)
+
+ return gnucash_simple.billToDict(bill)
+
+def addEntry(book, invoice_id, date, description, account_guid, quantity, price):
+
+ invoice = getGnuCashInvoice(book, invoice_id)
+
+ if invoice is None:
+ raise Error('NoInvoice',
+ 'No invoice exists with this ID', {'field': 'invoice_id'})
+
+ try:
+ date = datetime.datetime.strptime(date, "%Y-%m-%d")
+ except ValueError:
+ raise Error('InvalidDateOpened',
+ 'The date opened must be provided in the form YYYY-MM-DD',
+ {'field': 'date'})
+
+ guid = gnucash.gnucash_core.GUID()
+ gnucash.gnucash_core.GUIDString(account_guid, guid)
+
+ account = guid.AccountLookup(book)
+
+ if account is None:
+ raise Error('NoAccount', 'No account exists with this GUID',
+ {'field': 'account_guid'})
+
+ try:
+ quantity = Decimal(quantity).quantize(Decimal('.01'))
+ except ArithmeticError:
+ raise Error('InvalidQuantity', 'This quantity is not valid',
+ {'field': 'quantity'})
+
+ try:
+ price = Decimal(price).quantize(Decimal('.01'))
+ except ArithmeticError:
+ raise Error('InvalidPrice', 'This price is not valid',
+ {'field': 'price'})
+
+ entry = Entry(book, invoice, date.date())
+ entry.SetDateEntered(datetime.datetime.now())
+ entry.SetDescription(description)
+ entry.SetInvAccount(account)
+ entry.SetQuantity(gnc_numeric_from_decimal(quantity))
+ entry.SetInvPrice(gnc_numeric_from_decimal(price))
+
+ return gnucash_simple.entryToDict(entry)
+
+def addBillEntry(book, bill_id, date, description, account_guid, quantity,
+ price):
+
+ bill = getGnuCashBill(book,bill_id)
+
+ if bill is None:
+ raise Error('NoBill', 'No bill exists with this ID',
+ {'field': 'bill_id'})
+
+ try:
+ date = datetime.datetime.strptime(date, "%Y-%m-%d")
+ except ValueError:
+ raise Error('InvalidDateOpened',
+ 'The date opened must be provided in the form YYYY-MM-DD',
+ {'field': 'date'})
+
+ guid = gnucash.gnucash_core.GUID()
+ gnucash.gnucash_core.GUIDString(account_guid, guid)
+
+ account = guid.AccountLookup(book)
+
+ if account is None:
+ raise Error('NoAccount', 'No account exists with this GUID',
+ {'field': 'account_guid'})
+
+ try:
+ quantity = Decimal(quantity).quantize(Decimal('.01'))
+ except ArithmeticError:
+ raise Error('InvalidQuantity', 'This quantity is not valid',
+ {'field': 'quantity'})
+
+ try:
+ price = Decimal(price).quantize(Decimal('.01'))
+ except ArithmeticError:
+ raise Error('InvalidPrice', 'This price is not valid',
+ {'field': 'price'})
+
+ entry = Entry(book, bill, date.date())
+ entry.SetDateEntered(datetime.datetime.now())
+ entry.SetDescription(description)
+ entry.SetBillAccount(account)
+ entry.SetQuantity(gnc_numeric_from_decimal(quantity))
+ entry.SetBillPrice(gnc_numeric_from_decimal(price))
+
+ return gnucash_simple.entryToDict(entry)
+
+def getEntry(book, entry_guid):
+
+ guid = gnucash.gnucash_core.GUID()
+ gnucash.gnucash_core.GUIDString(entry_guid, guid)
+
+ entry = book.EntryLookup(guid)
+
+ if entry is None:
+ return None
+ else:
+ return gnucash_simple.entryToDict(entry)
+
+def updateEntry(book, entry_guid, date, description, account_guid, quantity,
+ price):
+
+ guid = gnucash.gnucash_core.GUID()
+ gnucash.gnucash_core.GUIDString(entry_guid, guid)
+
+ entry = book.EntryLookup(guid)
+
+ if entry is None:
+ raise Error('NoEntry', 'No entry exists with this GUID',
+ {'field': 'entry_guid'})
+
+ try:
+ date = datetime.datetime.strptime(date, "%Y-%m-%d")
+ except ValueError:
+ raise Error('InvalidDateOpened',
+ 'The date opened must be provided in the form YYYY-MM-DD',
+ {'field': 'date'})
+
+ gnucash.gnucash_core.GUIDString(account_guid, guid)
+
+ account = guid.AccountLookup(book)
+
+ if account is None:
+ raise Error('NoAccount', 'No account exists with this GUID',
+ {'field': 'account_guid'})
+
+ entry.SetDate(date.date())
+ entry.SetDateEntered(datetime.datetime.now())
+ entry.SetDescription(description)
+ entry.SetInvAccount(account)
+ entry.SetQuantity(
+ gnc_numeric_from_decimal(Decimal(quantity).quantize(Decimal('.01'))))
+ entry.SetInvPrice(
+ gnc_numeric_from_decimal(Decimal(price).quantize(Decimal('.01'))))
+
+ return gnucash_simple.entryToDict(entry)
+
+def deleteEntry(book, entry_guid):
+
+ guid = gnucash.gnucash_core.GUID()
+ gnucash.gnucash_core.GUIDString(entry_guid, guid)
+
+ entry = book.EntryLookup(guid)
+
+ invoice = entry.GetInvoice()
+ bill = entry.GetBill()
+
+ if invoice != None and entry != None:
+ invoice.RemoveEntry(entry)
+ elif bill != None and entry != None:
+ bill.RemoveEntry(entry)
+
+ if entry != None:
+ entry.Destroy()
+
+def deleteTransaction(book, transaction_guid):
+
+ guid = gnucash.gnucash_core.GUID()
+ gnucash.gnucash_core.GUIDString(transaction_guid, guid)
+
+ transaction = guid.TransLookup(book)
+
+ if transaction != None :
+ transaction.Destroy()
+
+def addBill(book, id, vendor_id, currency_mnumonic, date_opened, notes):
+
+ vendor = book.VendorLookupByID(vendor_id)
+
+ if vendor is None:
+ raise Error('NoVendor', 'A vendor with this ID does not exist',
+ {'field': 'id'})
+
+ if id is None:
+ id = book.BillNextID(vendor)
+
+ try:
+ date_opened = datetime.datetime.strptime(date_opened, "%Y-%m-%d")
+ except ValueError:
+ raise Error('InvalidVendorDateOpened',
+ 'The date opened must be provided in the form YYYY-MM-DD',
+ {'field': 'date_opened'})
+
+ if currency_mnumonic is None:
+ currency_mnumonic = vendor.GetCurrency().get_mnemonic()
+
+ commod_table = book.get_table()
+ currency = commod_table.lookup('CURRENCY', currency_mnumonic)
+
+ if currency is None:
+ raise Error('InvalidVendorCurrency',
+ 'A valid currency must be supplied for this vendor',
+ {'field': 'currency'})
+
+ bill = Bill(book, id, currency, vendor, date_opened.date())
+
+ bill.SetNotes(notes)
+
+ return gnucash_simple.billToDict(bill)
+
+def addAccount(book, name, currency_mnumonic, account_guid):
+
+ from gnucash.gnucash_core_c import \
+ ACCT_TYPE_ASSET, ACCT_TYPE_RECEIVABLE, ACCT_TYPE_INCOME, \
+ GNC_OWNER_CUSTOMER, ACCT_TYPE_LIABILITY
+
+ root_account = book.get_root_account()
+
+ commod_table = book.get_table()
+ currency = commod_table.lookup('CURRENCY', currency_mnumonic)
+
+ if currency is None:
+ raise Error('InvalidCustomerCurrency',
+ 'A valid currency must be supplied for this customer',
+ {'field': 'currency'})
+
+ account = Account(book)
+ root_account.append_child(root_account)
+ account.SetName(name)
+ account.SetType(ACCT_TYPE_ASSET)
+ account.SetCommodity(currency)
+
+def addTransaction(book, num, description, date_posted, currency_mnumonic, splits):
+
+ transaction = Transaction(book)
+
+ transaction.BeginEdit()
+
+ commod_table = book.get_table()
+ currency = commod_table.lookup('CURRENCY', currency_mnumonic)
+
+ if currency is None:
+ raise Error('InvalidTransactionCurrency',
+ 'A valid currency must be supplied for this transaction',
+ {'field': 'currency'})
+
+ try:
+ date_posted = datetime.datetime.strptime(date_posted, "%Y-%m-%d")
+ except ValueError:
+ raise Error('InvalidDatePosted',
+ 'The date posted must be provided in the form YYYY-MM-DD',
+ {'field': 'date_posted'})
+
+
+ for split_values in splits:
+ account_guid = gnucash.gnucash_core.GUID()
+ gnucash.gnucash_core.GUIDString(split_values['account_guid'], account_guid)
+
+ account = account_guid.AccountLookup(book)
+
+ if account is None:
+ raise Error('InvalidSplitAccount',
+ 'A valid account must be supplied for this split',
+ {'field': 'account'})
+
+ split = Split(book)
+ split.SetValue(GncNumeric(split_values['value'], 100))
+ split.SetAccount(account)
+ split.SetParent(transaction)
+
+ transaction.SetCurrency(currency)
+ transaction.SetDescription(description)
+ transaction.SetNum(num)
+
+ transaction.SetDatePostedTS(date_posted)
+
+ transaction.CommitEdit()
+
+ return gnucash_simple.transactionToDict(transaction, ['splits'])
+
+def getTransaction(book, transaction_guid):
+
+ guid = gnucash.gnucash_core.GUID()
+ gnucash.gnucash_core.GUIDString(transaction_guid, guid)
+
+ transaction = guid.TransLookup(book)
+
+ if transaction is None:
+ return None
+ else:
+ return gnucash_simple.transactionToDict(transaction, ['splits'])
+
+def editTransaction(book, transaction_guid, num, description, date_posted,
+ currency_mnumonic, splits):
+
+ guid = gnucash.gnucash_core.GUID()
+ gnucash.gnucash_core.GUIDString(transaction_guid, guid)
+
+ transaction = guid.TransLookup(book)
+
+ if transaction is None:
+ raise Error('NoCustomer',
+ 'A transaction with this GUID does not exist',
+ {'field': 'guid'})
+
+ transaction.BeginEdit()
+
+ commod_table = book.get_table()
+ currency = commod_table.lookup('CURRENCY', currency_mnumonic)
+
+ if currency is None:
+ raise Error('InvalidTransactionCurrency',
+ 'A valid currency must be supplied for this transaction',
+ {'field': 'currency'})
+
+
+ try:
+ date_posted = datetime.datetime.strptime(date_posted, "%Y-%m-%d")
+ except ValueError:
+ raise Error('InvalidDatePosted',
+ 'The date posted must be provided in the form YYYY-MM-DD',
+ {'field': 'date_posted'})
+
+ for split_values in splits:
+
+ split_guid = gnucash.gnucash_core.GUID()
+ gnucash.gnucash_core.GUIDString(split_values['guid'], split_guid)
+
+ split = split_guid.SplitLookup(book)
+
+ if split is None:
+ raise Error('InvalidSplitGuid',
+ 'A valid guid must be supplied for this split',
+ {'field': 'guid'})
+
+ account_guid = gnucash.gnucash_core.GUID()
+ gnucash.gnucash_core.GUIDString(
+ split_values['account_guid'], account_guid)
+
+ account = account_guid.AccountLookup(book)
+
+ if account is None:
+ raise Error('InvalidSplitAccount',
+ 'A valid account must be supplied for this split',
+ {'field': 'account'})
+
+ split.SetValue(GncNumeric(split_values['value'], 100))
+ split.SetAccount(account)
+ split.SetParent(transaction)
+
+ transaction.SetCurrency(currency)
+ transaction.SetDescription(description)
+ transaction.SetNum(num)
+
+ transaction.SetDatePostedTS(date_posted)
+
+ transaction.CommitEdit()
+
+ return gnucash_simple.transactionToDict(transaction, ['splits'])
+
+def gnc_numeric_from_decimal(decimal_value):
+ sign, digits, exponent = decimal_value.as_tuple()
+
+ # convert decimal digits to a fractional numerator
+ # equivlent to
+ # numerator = int(''.join(digits))
+ # but without the wated conversion to string and back,
+ # this is probably the same algorithm int() uses
+ numerator = 0
+ TEN = int(Decimal(0).radix()) # this is always 10
+ numerator_place_value = 1
+ # add each digit to the final value multiplied by the place value
+ # from least significant to most sigificant
+ for i in xrange(len(digits)-1,-1,-1):
+ numerator += digits[i] * numerator_place_value
+ numerator_place_value *= TEN
+
+ if decimal_value.is_signed():
+ numerator = -numerator
+
+ # if the exponent is negative, we use it to set the denominator
+ if exponent < 0 :
+ denominator = TEN ** (-exponent)
+ # if the exponent isn't negative, we bump up the numerator
+ # and set the denominator to 1
+ else:
+ numerator *= TEN ** exponent
+ denominator = 1
+
+ return GncNumeric(numerator, denominator)
def shutdown():
- session.end()
- session.destroy()
+ session.save()
+ session.end()
+ session.destroy()
+ print 'Shutdown'
+
+class Error(Exception):
+ """Base class for exceptions in this module."""
+ def __init__(self, type, message, data):
+ self.type = type
+ self.message = message
+ self.data = data
try:
- options, arguments = getopt.getopt(sys.argv[1:], 'h:', ['host='])
+ options, arguments = getopt.getopt(sys.argv[1:], 'nh:', ['host=', 'new='])
except getopt.GetoptError as err:
- print str(err) # will print something like "option -a not recognized"
- print 'Usage: python-rest.py <connection string>'
- sys.exit(2)
+ print str(err) # will print something like "option -a not recognized"
+ print 'Usage: python-rest.py <connection string>'
+ sys.exit(2)
-if len(arguments) != 1:
- print 'Usage: python-rest.py <connection string>'
- sys.exit(2)
+if len(arguments) == 0:
+ print 'Usage: python-rest.py <connection string>'
+ sys.exit(2)
-#set default host for flash
+#set default host for Flask
host = '127.0.0.1'
#allow host option to be changed
for option, value in options:
- if option in ("-h", "--host"):
- host = value
+ if option in ("-h", "--host"):
+ host = value
+
+is_new = False
+
+# allow a new database to be used
+for option, value in options:
+ if option in ("-n", "--new"):
+ is_new = True
+
#start gnucash session base on connection string argument
+if is_new:
+ session = gnucash.Session(arguments[0], is_new=True)
+
+ # seem to get errors if we use the session directly, so save it and
+ #destroy it so it's no longer new
+
+ session.save()
+ session.end()
+ session.destroy()
+
session = gnucash.Session(arguments[0], ignore_lock=True)
# register method to close gnucash connection gracefully
atexit.register(shutdown)
+app.debug = False
+
+# log to console
+if not app.debug:
+ import logging
+ from logging import StreamHandler
+ stream_handler = StreamHandler()
+ stream_handler.setLevel(logging.ERROR)
+ app.logger.addHandler(stream_handler)
+
# start Flask server
app.run(host=host)
diff --git a/src/optional/python-bindings/example_scripts/rest-api/gnucash_simple.py b/src/optional/python-bindings/example_scripts/rest-api/gnucash_simple.py
index 51e7632..509d7ac 100644
--- a/src/optional/python-bindings/example_scripts/rest-api/gnucash_simple.py
+++ b/src/optional/python-bindings/example_scripts/rest-api/gnucash_simple.py
@@ -1,152 +1,303 @@
+'''
+
+gnucash_simple.py -- A helper file to convert Gnucash objects into
+dictionaries for easier conversion to JSON
+
+Copyright (C) 2013 Tom Lofts <dev at loftx.co.uk>
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of
+the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, contact:
+
+Free Software Foundation Voice: +1-617-542-5942
+51 Franklin Street, Fifth Floor Fax: +1-617-542-2652
+Boston, MA 02110-1301, USA gnu at gnu.org
+
+ at author Tom Lofts <dev at loftx.co.uk>
+
+'''
+
import gnucash
-from gnucash.gnucash_business import Entry
+from gnucash.gnucash_business import Entry, Split, Account
def addressToDict(address):
- if address is None:
- return None
- else:
- simple_address = {}
- simple_address['name'] = address.GetName();
- simple_address['line_1'] = address.GetAddr1();
- simple_address['line_2'] = address.GetAddr2();
- simple_address['line_3'] = address.GetAddr3();
- simple_address['line_4'] = address.GetAddr4();
- simple_address['phone'] = address.GetPhone();
- simple_address['fax'] = address.GetFax();
- simple_address['email'] = address.GetEmail();
-
- return simple_address
+ if address is None:
+ return None
+ else:
+ simple_address = {}
+ simple_address['name'] = address.GetName();
+ simple_address['line_1'] = address.GetAddr1();
+ simple_address['line_2'] = address.GetAddr2();
+ simple_address['line_3'] = address.GetAddr3();
+ simple_address['line_4'] = address.GetAddr4();
+ simple_address['phone'] = address.GetPhone();
+ simple_address['fax'] = address.GetFax();
+ simple_address['email'] = address.GetEmail();
+
+ return simple_address
def vendorToDict(vendor):
- if vendor is None:
- return None
- else:
- simple_vendor = {}
- simple_vendor['name'] = vendor.GetName()
- simple_vendor['id'] = vendor.GetID()
- simple_vendor['notes'] = vendor.GetNotes()
- simple_vendor['active'] = vendor.GetActive()
- simple_vendor['currency'] = vendor.GetCurrency().get_mnemonic()
- simple_vendor['tax_table_override'] = vendor.GetTaxTableOverride()
- simple_vendor['address'] = addressToDict(vendor.GetAddr())
- simple_vendor['tax_included'] = vendor.GetTaxIncluded()
-
- return simple_vendor
+ if vendor is None:
+ return None
+ else:
+ simple_vendor = {}
+ simple_vendor['name'] = vendor.GetName()
+ simple_vendor['id'] = vendor.GetID()
+ simple_vendor['guid'] = vendor.GetGUID().to_string()
+ simple_vendor['notes'] = vendor.GetNotes()
+ simple_vendor['active'] = vendor.GetActive()
+ simple_vendor['currency'] = vendor.GetCurrency().get_mnemonic()
+ simple_vendor['tax_table_override'] = vendor.GetTaxTableOverride()
+ simple_vendor['address'] = addressToDict(vendor.GetAddr())
+ simple_vendor['tax_included'] = vendor.GetTaxIncluded()
+
+ return simple_vendor
def customerToDict(customer):
- if customer is None:
- return None
- else:
- simple_customer = {}
- simple_customer['name'] = customer.GetName()
- simple_customer['id'] = customer.GetID()
- simple_customer['notes'] = customer.GetNotes()
- simple_customer['active'] = customer.GetActive()
- simple_customer['discount'] = customer.GetDiscount().to_double()
- simple_customer['credit'] = customer.GetCredit().to_double()
- simple_customer['currency'] = customer.GetCurrency().get_mnemonic()
- simple_customer['tax_table_override'] = customer.GetTaxTableOverride()
- simple_customer['address'] = addressToDict(customer.GetAddr())
- simple_customer['shipping_address'] = addressToDict(customer.GetShipAddr())
- simple_customer['tax_included'] = customer.GetTaxIncluded()
-
- return simple_customer
-
-def transactionToDict(transaction):
- if transaction is None:
- return None
- else:
- simple_transaction = {}
- simple_transaction['num'] = transaction.GetNum()
- simple_transaction['notes'] = transaction.GetNotes()
- simple_transaction['is_closing_txn'] = transaction.GetIsClosingTxn()
- simple_transaction['count_splits'] = transaction.CountSplits()
- simple_transaction['has_reconciled_splits'] = transaction.HasReconciledSplits()
- simple_transaction['currency'] = transaction.GetCurrency().get_mnemonic()
- simple_transaction['imbalance_value'] = transaction.GetImbalanceValue().to_double()
- simple_transaction['is_balanced'] = transaction.IsBalanced()
- simple_transaction['date'] = transaction.GetDate()
- simple_transaction['date_posted'] = transaction.RetDatePostedTS().strftime('%Y-%m-%d')
- simple_transaction['date_entered'] = transaction.RetDateEnteredTS().strftime('%Y-%m-%d')
- simple_transaction['date_due'] = transaction.RetDateDueTS().strftime('%Y-%m-%d')
- simple_transaction['void_status'] = transaction.GetVoidStatus()
- simple_transaction['void_time'] = transaction.GetVoidTime().strftime('%Y-%m-%d')
-
- return simple_transaction
+ if customer is None:
+ return None
+ else:
+ simple_customer = {}
+ simple_customer['name'] = customer.GetName()
+ simple_customer['id'] = customer.GetID()
+ simple_customer['guid'] = customer.GetGUID().to_string()
+ simple_customer['notes'] = customer.GetNotes()
+ simple_customer['active'] = customer.GetActive()
+ simple_customer['discount'] = customer.GetDiscount().to_double()
+ simple_customer['credit'] = customer.GetCredit().to_double()
+ simple_customer['currency'] = customer.GetCurrency().get_mnemonic()
+ simple_customer['tax_table_override'] = customer.GetTaxTableOverride()
+ simple_customer['address'] = addressToDict(customer.GetAddr())
+ simple_customer['shipping_address'] = addressToDict(
+ customer.GetShipAddr())
+ simple_customer['tax_included'] = customer.GetTaxIncluded()
+
+ return simple_customer
+
+def transactionToDict(transaction, entities):
+ if transaction is None:
+ return None
+ else:
+ simple_transaction = {}
+ simple_transaction['guid'] = transaction.GetGUID().to_string()
+ simple_transaction['num'] = transaction.GetNum()
+ simple_transaction['notes'] = transaction.GetNotes()
+ simple_transaction['is_closing_txn'] = transaction.GetIsClosingTxn()
+
+ if 'splits' in entities:
+ simple_transaction['splits'] = []
+ for split in transaction.GetSplitList():
+ if type(split) != Split:
+ split=Split(instance=split)
+ simple_transaction['splits'].append(
+ splitToDict(split, ['account']))
+
+ simple_transaction['count_splits'] = transaction.CountSplits()
+ simple_transaction['has_reconciled_splits'] = \
+ transaction.HasReconciledSplits()
+ simple_transaction['currency'] = transaction.GetCurrency(
+ ).get_mnemonic()
+ simple_transaction['imbalance_value'] = transaction.GetImbalanceValue(
+ ).to_double()
+ simple_transaction['is_balanced'] = transaction.IsBalanced()
+ simple_transaction['date'] = transaction.GetDate()
+ simple_transaction['date_posted'] = transaction.RetDatePostedTS(
+ ).strftime('%Y-%m-%d')
+ simple_transaction['date_entered'] = transaction.RetDateEnteredTS(
+ ).strftime('%Y-%m-%d')
+ simple_transaction['date_due'] = transaction.RetDateDueTS().strftime(
+ '%Y-%m-%d')
+ simple_transaction['void_status'] = transaction.GetVoidStatus()
+ simple_transaction['void_time'] = transaction.GetVoidTime().strftime(
+ '%Y-%m-%d')
+
+ simple_transaction['description'] = transaction.GetDescription()
+ return simple_transaction
+
+def splitToDict(split, entities):
+ if split is None:
+ return None
+ else:
+ simple_split = {}
+ simple_split['guid'] = split.GetGUID().to_string()
+ if 'account' in entities:
+ simple_split['account'] = accountToDict(split.GetAccount())
+ if 'transaction' in entities:
+ simple_split['transaction'] = transactionToDict(
+ split.GetParent(), [])
+ if 'other_split' in entities:
+ simple_split['other_split'] = splitToDict(
+ split.GetOtherSplit(), ['account'])
+ simple_split['amount'] = split.GetAmount().to_double()
+ simple_split['value'] = split.GetValue().to_double()
+ simple_split['balance'] = split.GetBalance().to_double()
+ simple_split['cleared_balance'] = split.GetClearedBalance().to_double()
+ simple_split['reconciled_balance'] = split.GetReconciledBalance(
+ ).to_double()
+
+ return simple_split
def invoiceToDict(invoice):
- if invoice is None:
- return None
- else:
- simple_invoice = {}
- simple_invoice['id'] = invoice.GetID()
- simple_invoice['type'] = invoice.GetType()
- simple_invoice['date_opened'] = invoice.GetDateOpened().strftime('%Y-%m-%d')
- simple_invoice['date_posted'] = invoice.GetDatePosted().strftime('%Y-%m-%d')
- simple_invoice['date_due'] = invoice.GetDateDue().strftime('%Y-%m-%d')
- simple_invoice['notes'] = invoice.GetNotes()
- simple_invoice['active'] = invoice.GetActive()
- simple_invoice['currency'] = invoice.GetCurrency().get_mnemonic()
- simple_invoice['owner'] = vendorToDict(invoice.GetOwner())
- simple_invoice['owner_type'] = invoice.GetOwnerType()
- simple_invoice['billing_id'] = invoice.GetBillingID()
- simple_invoice['to_charge_amount'] = invoice.GetToChargeAmount().to_double()
- simple_invoice['total'] = invoice.GetTotal().to_double()
- simple_invoice['total_subtotal'] = invoice.GetTotalSubtotal().to_double()
- simple_invoice['total_tax'] = invoice.GetTotalTax().to_double()
- simple_invoice['entries'] = {}
- for n, entry in enumerate(invoice.GetEntries()):
- if type(entry) != Entry:
- entry=Entry(instance=entry)
- simple_invoice['entries'][n] = entryToDict(entry)
- simple_invoice['posted'] = invoice.IsPosted()
- simple_invoice['paid'] = invoice.IsPaid()
-
- return simple_invoice
+ if invoice is None:
+ return None
+ else:
+ simple_invoice = {}
+ simple_invoice['id'] = invoice.GetID()
+ simple_invoice['type'] = invoice.GetType()
+ simple_invoice['date_opened'] = invoice.GetDateOpened().strftime(
+ '%Y-%m-%d')
+ if invoice.GetDatePosted().strftime('%Y-%m-%d') == '1970-01-01':
+ simple_invoice['date_posted'] = None
+ else:
+ simple_invoice['date_posted'] = invoice.GetDatePosted().strftime(
+ '%Y-%m-%d')
+ if invoice.GetDateDue().strftime('%Y-%m-%d') == '1970-01-01':
+ simple_invoice['date_due'] = None
+ else:
+ simple_invoice['date_due'] = invoice.GetDateDue().strftime(
+ '%Y-%m-%d')
+ simple_invoice['notes'] = invoice.GetNotes()
+ simple_invoice['active'] = invoice.GetActive()
+ simple_invoice['currency'] = invoice.GetCurrency().get_mnemonic()
+ simple_invoice['owner'] = vendorToDict(invoice.GetOwner())
+ simple_invoice['owner_type'] = invoice.GetOwnerType()
+ simple_invoice['billing_id'] = invoice.GetBillingID()
+ simple_invoice['to_charge_amount'] = invoice.GetToChargeAmount().to_double()
+ simple_invoice['posted_txn'] = transactionToDict(invoice.GetPostedTxn(), [])
+ simple_invoice['total'] = invoice.GetTotal().to_double()
+ simple_invoice['total_subtotal'] = invoice.GetTotalSubtotal(
+ ).to_double()
+ simple_invoice['total_tax'] = invoice.GetTotalTax().to_double()
+
+ simple_invoice['entries'] = []
+ for n, entry in enumerate(invoice.GetEntries()):
+ if type(entry) != Entry:
+ entry=Entry(instance=entry)
+ simple_invoice['entries'].append(entryToDict(entry))
+
+ simple_invoice['posted'] = invoice.IsPosted()
+ simple_invoice['paid'] = invoice.IsPaid()
+
+ return simple_invoice
+
+def billToDict(bill):
+
+ if bill is None:
+ return None
+ else:
+ simple_bill = {}
+ simple_bill['id'] = bill.GetID()
+ simple_bill['type'] = bill.GetType()
+ simple_bill['date_opened'] = bill.GetDateOpened().strftime('%Y-%m-%d')
+ if bill.GetDatePosted().strftime('%Y-%m-%d') == '1970-01-01':
+ simple_bill['date_posted'] = None
+ else:
+ simple_bill['date_posted'] = bill.GetDatePosted().strftime(
+ '%Y-%m-%d')
+ if bill.GetDateDue().strftime('%Y-%m-%d') == '1970-01-01':
+ simple_bill['date_due'] = None
+ else:
+ simple_bill['date_due'] = bill.GetDateDue().strftime('%Y-%m-%d')
+ simple_bill['notes'] = bill.GetNotes()
+ simple_bill['active'] = bill.GetActive()
+ simple_bill['currency'] = bill.GetCurrency().get_mnemonic()
+ simple_bill['owner'] = vendorToDict(bill.GetOwner())
+ simple_bill['owner_type'] = bill.GetOwnerType()
+ simple_bill['billing_id'] = bill.GetBillingID()
+ simple_bill['to_charge_amount'] = bill.GetToChargeAmount().to_double()
+ simple_bill['total'] = bill.GetTotal().to_double()
+ simple_bill['total_subtotal'] = bill.GetTotalSubtotal().to_double()
+ simple_bill['total_tax'] = bill.GetTotalTax().to_double()
+
+ simple_bill['entries'] = []
+ for n, entry in enumerate(bill.GetEntries()):
+ if type(entry) != Entry:
+ entry=Entry(instance=entry)
+ simple_bill['entries'].append(entryToDict(entry))
+
+ simple_bill['posted'] = bill.IsPosted()
+ simple_bill['paid'] = bill.IsPaid()
+
+ return simple_bill
def entryToDict(entry):
- if entry is None:
- return None
- else:
- simple_entry = {}
- simple_entry['date'] = entry.GetDate().strftime('%Y-%m-%d')
- simple_entry['date_entered'] = entry.GetDateEntered().strftime('%Y-%m-%d')
- simple_entry['description'] = entry.GetDescription()
- simple_entry['action'] = entry.GetAction()
- simple_entry['notes'] = entry.GetNotes()
- simple_entry['quantity'] = gnucash.GncNumeric(instance=entry.GetQuantity()).to_double()
- simple_entry['inv_price'] = gnucash.GncNumeric(instance=entry.GetInvPrice()).to_double()
- simple_entry['discount'] = gnucash.GncNumeric(instance=entry.GetInvDiscount()).to_double()
- simple_entry['discounted_type'] = entry.GetInvDiscountType()
- simple_entry['discounted_how'] = entry.GetInvDiscountHow()
- simple_entry['inv_taxable'] = entry.GetInvTaxable()
- simple_entry['inv_tax_included'] = entry.GetInvTaxIncluded()
- simple_entry['inv_tax_table_override'] = entry.GetInvTaxTable()
- simple_entry['bill_price'] = gnucash.GncNumeric(instance=entry.GetBillPrice()).to_double()
- simple_entry['bill_taxable'] = entry.GetBillTaxable()
- simple_entry['bill_tax_included'] = entry.GetBillTaxIncluded()
- simple_entry['bill_tax_table'] = entry.GetBillTaxTable()
- simple_entry['billable'] = entry.GetBillable()
- simple_entry['bill_payment'] = entry.GetBillPayment()
- simple_entry['is_open'] = entry.IsOpen()
-
- return simple_entry
+ if entry is None:
+ return None
+ else:
+
+ simple_entry = {}
+ simple_entry['guid'] = entry.GetGUID().to_string()
+ simple_entry['date'] = entry.GetDate().strftime('%Y-%m-%d')
+ simple_entry['date_entered'] = entry.GetDateEntered().strftime(
+ '%Y-%m-%d')
+ simple_entry['description'] = entry.GetDescription()
+ simple_entry['action'] = entry.GetAction()
+ simple_entry['notes'] = entry.GetNotes()
+ simple_entry['quantity'] = entry.GetQuantity().to_double()
+ if entry.GetInvAccount() == None:
+ simple_entry['inv_account'] = {}
+ else:
+ simple_entry['inv_account'] = accountToDict(entry.GetInvAccount())
+ simple_entry['inv_price'] = entry.GetInvPrice().to_double()
+ simple_entry['discount'] = entry.GetInvDiscount().to_double()
+ simple_entry['discounted_type'] = entry.GetInvDiscountType()
+ simple_entry['discounted_how'] = entry.GetInvDiscountHow()
+ simple_entry['inv_taxable'] = entry.GetInvTaxable()
+ simple_entry['inv_tax_included'] = entry.GetInvTaxIncluded()
+ simple_entry['inv_tax_table_override'] = entry.GetInvTaxTable()
+ if entry.GetBillAccount() == None:
+ simple_entry['bill_account'] = {}
+ else:
+ simple_entry['bill_account'] = accountToDict(
+ entry.GetBillAccount())
+ simple_entry['bill_price'] = entry.GetBillPrice().to_double()
+ simple_entry['bill_taxable'] = entry.GetBillTaxable()
+ simple_entry['bill_tax_included'] = entry.GetBillTaxIncluded()
+ simple_entry['bill_tax_table'] = entry.GetBillTaxTable()
+ simple_entry['billable'] = entry.GetBillable()
+ simple_entry['bill_payment'] = entry.GetBillPayment()
+ simple_entry['is_open'] = entry.IsOpen()
+
+ return simple_entry
def accountToDict(account):
- if account is None:
- return None
- else:
- simple_account = {}
- simple_account['name'] = account.GetName()
- simple_account['guid'] = account.GetGUID().to_string()
- simple_account['subaccounts'] = []
- for n, subaccount in enumerate(account.get_children_sorted()):
- simple_account['subaccounts'].append(accountToDict(subaccount))
-
- return simple_account
\ No newline at end of file
+ commod_table = account.get_book().get_table()
+ gbp = commod_table.lookup('CURRENCY', 'GBP')
+
+ if account is None:
+ return None
+ else:
+ simple_account = {}
+ simple_account['name'] = account.GetName()
+ simple_account['type_id'] = account.GetType()
+ simple_account['description'] = account.GetDescription()
+ simple_account['guid'] = account.GetGUID().to_string()
+ if account.GetCommodity() == None:
+ simple_account['currency'] = ''
+ else:
+ simple_account['currency'] = account.GetCommodity().get_mnemonic()
+ simple_account['subaccounts'] = []
+ for n, subaccount in enumerate(account.get_children_sorted()):
+ simple_account['subaccounts'].append(accountToDict(subaccount))
+
+ simple_account['balance'] = account.GetBalance().to_double()
+ simple_account['balance_gbp'] = account.GetBalanceInCurrency(
+ gbp, True).to_double()
+ simple_account['placeholder'] = account.GetPlaceholder()
+
+ return simple_account
diff --git a/src/optional/python-bindings/gnucash_business.py b/src/optional/python-bindings/gnucash_business.py
index 930c6d8..b03ce01 100644
--- a/src/optional/python-bindings/gnucash_business.py
+++ b/src/optional/python-bindings/gnucash_business.py
@@ -35,7 +35,7 @@ from function_class import \
from gnucash_core import \
GnuCashCoreClass, GncNumeric, GncCommodity, Transaction, \
- Split, Book, GncLot, Account
+ Split, Book, GncLot, Account, GUID
from gnucash_core_c import GNC_OWNER_CUSTOMER, GNC_OWNER_JOB, \
GNC_OWNER_EMPLOYEE, GNC_OWNER_VENDOR, \
@@ -217,8 +217,7 @@ class Entry(GnuCashCoreClass):
if invoice != None:
invoice.AddEntry(self)
else:
-
- GnuCashCoreClass.__init__(self, instance=instance)
+ GnuCashCoreClass.__init__(self, instance=instance)
def test_type(self, invoice):
if invoice.GetTypeString() == "Invoice" and self.GetInvoice() == None:
@@ -226,11 +225,11 @@ class Entry(GnuCashCoreClass):
if invoice.GetTypeString() == "Bill" and self.GetBill() == None:
raise Exception("Entry type error. Check that Entry type matches Bill.")
-
# Owner
GnuCashBusinessEntity.add_methods_with_prefix('gncOwner')
owner_dict = {
+ 'GetGUID' : GUID,
'GetCustomer' : Customer,
'GetVendor' : Vendor,
'GetEmployee' : Employee,
@@ -249,6 +248,7 @@ methods_return_instance_lists(
# Customer
Customer.add_constructor_and_methods_with_prefix('gncCustomer', 'Create')
+Customer.add_method('gncOwnerApplyPayment', 'ApplyPayment')
customer_dict = {
'GetAddr' : Address,
@@ -326,6 +326,8 @@ Invoice.add_constructor_and_methods_with_prefix('gncInvoice', 'Create')
methods_return_instance_lists(
Invoice, { 'GetEntries': Entry })
+Invoice.add_method('gncInvoiceRemoveEntry', 'RemoveEntry')
+
# Bill
Bill.add_methods_with_prefix('gncBill')
@@ -351,7 +353,11 @@ Invoice.decorate_functions(
# Entry
Entry.add_constructor_and_methods_with_prefix('gncEntry', 'Create')
+Entry.add_method('gncEntryGetGUID', 'GetGUID')
+Entry.add_method('gncEntryDestroy', 'Destroy')
+
entry_dict = {
+ 'GetGUID' : GUID,
'GetQuantity': GncNumeric,
'GetInvAccount': Account,
'GetInvPrice': GncNumeric,
diff --git a/src/optional/python-bindings/gnucash_core.i b/src/optional/python-bindings/gnucash_core.i
index 13aef43..213c823 100644
--- a/src/optional/python-bindings/gnucash_core.i
+++ b/src/optional/python-bindings/gnucash_core.i
@@ -124,23 +124,23 @@
PyObject * swig_wrapper_object;
if (owner_type == GNC_OWNER_CUSTOMER ){
swig_wrapper_object = SWIG_NewPointerObj(
- gncOwnerGetCustomer($1), $descriptor(GncCustomer *), 0);
+ gncOwnerGetCustomer($1), $descriptor(GncCustomer *), 0);
}
else if (owner_type == GNC_OWNER_JOB){
swig_wrapper_object = SWIG_NewPointerObj(
- gncOwnerGetJob($1), $descriptor(GncJob *), 0);
+ gncOwnerGetJob($1), $descriptor(GncJob *), 0);
}
else if (owner_type == GNC_OWNER_VENDOR){
swig_wrapper_object = SWIG_NewPointerObj(
- gncOwnerGetVendor($1), $descriptor(GncVendor *), 0);
+ gncOwnerGetVendor($1), $descriptor(GncVendor *), 0);
}
else if (owner_type == GNC_OWNER_EMPLOYEE){
swig_wrapper_object = SWIG_NewPointerObj(
- gncOwnerGetEmployee($1), $descriptor(GncEmployee *), 0);
+ gncOwnerGetEmployee($1), $descriptor(GncEmployee *), 0);
}
else {
swig_wrapper_object = Py_None;
- Py_INCREF(Py_None);
+ Py_INCREF(Py_None);
}
PyTuple_SetItem(owner_tuple, 1, swig_wrapper_object);
$result = owner_tuple;
@@ -175,10 +175,10 @@
$1 = temp_owner;
}
else {
- PyErr_SetString(
- PyExc_ValueError,
- "Python object passed to function with GncOwner * argument "
- "couldn't be converted back to pointer of that type");
+ PyErr_SetString(
+ PyExc_ValueError,
+ "Python object passed to function with GncOwner * argument "
+ "couldn't be converted back to pointer of that type");
return NULL;
}
}
@@ -187,6 +187,7 @@
gncOwnerFree($1);
}
+static const GncGUID * gncEntryGetGUID(GncEntry *x);
%include <gnc-lot.h>
diff --git a/src/optional/python-bindings/gnucash_core.py b/src/optional/python-bindings/gnucash_core.py
index 578e800..af9e007 100644
--- a/src/optional/python-bindings/gnucash_core.py
+++ b/src/optional/python-bindings/gnucash_core.py
@@ -40,8 +40,9 @@ from gnucash_core_c import gncInvoiceLookup, gncInvoiceGetInvoiceFromTxn, \
gncInvoiceGetInvoiceFromLot, gncEntryLookup, gncInvoiceLookup, \
gncCustomerLookup, gncVendorLookup, gncJobLookup, gncEmployeeLookup, \
gncTaxTableLookup, gncTaxTableLookupByName, gnc_search_invoice_on_id, \
- gnc_search_customer_on_id, gnc_search_bill_on_id , gnc_search_vendor_on_id, \
- gncInvoiceNextID, gncCustomerNextID, gncTaxTableGetTables, gncVendorNextID
+ gnc_search_customer_on_id, gnc_search_bill_on_id , \
+ gnc_search_vendor_on_id, gncInvoiceNextID, gncCustomerNextID, \
+ gncVendorNextID, gncTaxTableGetTables
class GnuCashCoreClass(ClassFromFunctions):
_module = gnucash_core_c
@@ -176,7 +177,7 @@ class Book(GnuCashCoreClass):
gncInvoiceLookup, Invoice, guid.get_instance() )
def EntryLookup(self, guid):
- from gnucash_business import Entr
+ from gnucash_business import Entry
return self.do_lookup_create_oo_instance(
gncEntryLookup, Entry, guid.get_instance() )
@@ -214,7 +215,7 @@ class Book(GnuCashCoreClass):
from gnucash_business import TaxTable
return [ TaxTable(instance=item) for item in gncTaxTableGetTables(self.instance) ]
- def BillLoookupByID(self, id):
+ def BillLookupByID(self, id):
from gnucash_business import Bill
return self.do_lookup_create_oo_instance(
gnc_search_bill_on_id, Bill, id)
@@ -249,7 +250,7 @@ class Book(GnuCashCoreClass):
''' Return the next Customer ID. '''
from gnucash.gnucash_core_c import gncCustomerNextID
return gncCustomerNextID(self.get_instance())
-
+
def VendorNextID(self):
''' Return the next Vendor ID. '''
from gnucash.gnucash_core_c import gncVendorNextID
@@ -581,6 +582,9 @@ methods_return_instance(GncLot, gnclot_dict)
Transaction.add_methods_with_prefix('xaccTrans')
Transaction.add_method('gncTransGetGUID', 'GetGUID');
+Transaction.add_method('xaccTransGetDescription', 'GetDescription')
+Transaction.add_method('xaccTransDestroy', 'Destroy')
+
trans_dict = {
'GetSplit': Split,
'FindSplitByAccount': Split,
@@ -606,6 +610,7 @@ Transaction.decorate_functions(
# Split
Split.add_methods_with_prefix('xaccSplit')
Split.add_method('gncSplitGetGUID', 'GetGUID');
+Split.add_method('xaccSplitDestroy', 'Destroy')
split_dict = {
'GetBook': Book,
@@ -634,6 +639,7 @@ Split.parent = property( Split.GetParent, Split.SetParent )
Account.add_methods_with_prefix('xaccAccount')
Account.add_methods_with_prefix('gnc_account_')
Account.add_method('gncAccountGetGUID', 'GetGUID');
+Account.add_method('xaccAccountGetPlaceholder', 'GetPlaceholder')
account_dict = {
'get_book' : Book,
@@ -734,19 +740,36 @@ Query.add_method('qof_query_search_for', 'search_for')
Query.add_method('qof_query_run', 'run')
Query.add_method('qof_query_add_term', 'add_term')
Query.add_method('qof_query_add_boolean_match', 'add_boolean_match')
+Query.add_method('qof_query_add_guid_list_match', 'add_guid_list_match')
+Query.add_method('qof_query_add_guid_match', 'add_guid_match')
Query.add_method('qof_query_destroy', 'destroy')
class QueryStringPredicate(GnuCashCoreClass):
pass
-QueryStringPredicate.add_constructor_and_methods_with_prefix('qof_query_', 'string_predicate')
+QueryStringPredicate.add_constructor_and_methods_with_prefix(
+ 'qof_query_','string_predicate')
class QueryBooleanPredicate(GnuCashCoreClass):
pass
-QueryBooleanPredicate.add_constructor_and_methods_with_prefix('qof_query_', 'boolean_predicate')
+QueryBooleanPredicate.add_constructor_and_methods_with_prefix(
+ 'qof_query_', 'boolean_predicate')
class QueryInt32Predicate(GnuCashCoreClass):
pass
-QueryInt32Predicate.add_constructor_and_methods_with_prefix('qof_query_', 'int32_predicate')
+QueryInt32Predicate.add_constructor_and_methods_with_prefix(
+ 'qof_query_', 'int32_predicate')
+
+class QueryDatePredicate(GnuCashCoreClass):
+ pass
+
+QueryDatePredicate.add_constructor_and_methods_with_prefix(
+ 'qof_query_', 'date_predicate')
+
+class QueryGuidPredicate(GnuCashCoreClass):
+ pass
+
+QueryGuidPredicate.add_constructor_and_methods_with_prefix(
+ 'qof_query_', 'guid_predicate')
Summary of changes:
.../example_scripts/rest-api/README | 230 ++-
.../example_scripts/rest-api/gnucash_rest.py | 1912 ++++++++++++++++++--
.../example_scripts/rest-api/gnucash_simple.py | 417 +++--
src/optional/python-bindings/gnucash_business.py | 14 +-
src/optional/python-bindings/gnucash_core.i | 19 +-
src/optional/python-bindings/gnucash_core.py | 39 +-
6 files changed, 2337 insertions(+), 294 deletions(-)
mode change 100755 => 100644 src/optional/python-bindings/example_scripts/rest-api/gnucash_rest.py
More information about the gnucash-changes
mailing list