.. _generating: Generating OFX ============== Creating your own OFX requests or responses - as would be neeeded for, say, a Python-powered OFX server - is fairly straightforward. However, you will need to be pretty familiar with the OFX spec. ``ofxtools`` validates individual nodes in the hierarchy, but doesn't really do anything to verify compliant sequence order, for example. It doesn't validate against a DTD. That is on you, friend. Don't forget to make datetimes timezone-aware. As an example, we'll create a trivial bank statement response. You can follow along in section 11.4.2.2 of the OFX spec. .. code:: python In [1]: from ofxtools.models import * In [2]: from ofxtools.utils import UTC In [3]: from decimal import Decimal In [4]: from datetime import datetime In [5]: ledgerbal = LEDGERBAL(balamt=Decimal('150.65'), ...: dtasof=datetime(2015, 1, 1, tzinfo=UTC)) In [6]: acctfrom = BANKACCTFROM(bankid='123456789', ...: acctid='23456', accttype='CHECKING') # OFX Section 11.3.1 In [7]: stmtrs = STMTRS(curdef='USD', bankacctfrom=acctfrom, ...: ledgerbal=ledgerbal) So far so good. Now to slather it in wrapper cruft and garnish with metadata. .. code:: python In [8]: status = STATUS(code=0, severity='INFO') In [9]: stmttrnrs = STMTTRNRS(trnuid='5678', status=status, stmtrs=stmtrs) In [10]: bankmsgsrs = BANKMSGSRSV1(stmttrnrs) In [11]: fi = FI(org='Illuminati', fid='666') # Required for Quicken compatibility In [12]: sonrs = SONRS(status=status, ...: dtserver=datetime(2015, 1, 2, 17, tzinfo=UTC), ...: language='ENG', fi=fi) In [13]: signonmsgs = SIGNONMSGSRSV1(sonrs=sonrs) In [14]: ofx = OFX(signonmsgsrsv1=signonmsgs, bankmsgsrsv1=bankmsgsrs) OK, that's the complete OFX message body. To serialize it, we transform the ``ofxtools.models`` structure back into an instance of ``xml.etree.ElementTree.ElementTree``. .. code:: python In [15]: import xml.etree.ElementTree as ET In [16]: root = ofx.to_etree() In [17]: message = ET.tostring(root).decode() In [18]: message Out[18]: '0INFO20150102170000ENGIlluminati66656780INFOUSD12345678923456CHECKING150.6520150101000000' One last step - we need to prepend an OFX header. .. code:: python In [19]: from ofxtools.header import make_header In [20]: header = str(make_header(version=220)) In [21]: header Out[21]: '\r\n\r\n' In [22]: response = header + message In [23]: response Out[23]: '\r\n\r\n0INFO20150102170000ENGIlluminati66656780INFOUSD12345678923456CHECKING150.6520150101000000' Hand that to your HTTP server, and off you go.