fix: populate OFX NAME field from Lloyds transaction descriptions#1
fix: populate OFX NAME field from Lloyds transaction descriptions#1Metasaura merged 9 commits intoMetasaura:mainfrom
Conversation
producing OFX output without a `<NAME>` element. Downstream importers use NAME as the primary transaction label, so: - Odoo displays ` : description` with a leading colon - Auto-reconciliation by payee/label fails completely - The Odoo reconciliation widget miscalculates balances when NAME is empty (see odoo/odoo#33104) Parse Lloyds description text per transaction type to extract a clean payee name for NAME, with the structured remainder as MEMO. The Lloyds transaction type code (DD, FPI, FPO, DEB etc.) is prefixed to the MEMO field, making it available for reconciliation rule matching via the Note condition. This preserves the Lloyds-specific codes that are lost in OFX TRNTYPE mapping (e.g. FPI and BGC both become CREDIT). Supported patterns: - FX purchases: `MERCHANT [ref] [CURRENCY] amount VISAXR rate CD nnnn` → NAME: `MERCHANT`, MEMO: `DEB amount VISAXR rate CD nnnn` - FX fees: `NON-GBP TRANS FEE n.nn% CD nnnn` → NAME: `Non-GBP Transaction Fee`, MEMO: `DEB 2.75% CD 1417` - Card payments: `MERCHANT CD nnnn [date]` → NAME: `MERCHANT`, MEMO: `DEB CD nnnn` - Faster payments in: `PAYEE ref sortcode ddMMMYY HH:MM` → NAME: `PAYEE`, MEMO: `FPI ref sortcode ddMMMYY HH:MM` - Faster payments out: same pattern → NAME: `PAYEE`, MEMO: `FPO ref sortcode ddMMMYY HH:MM` - Direct debits: `PAYEE mandate-ref` → NAME: `PAYEE`, MEMO: `DD mandate-ref` - Service charges: `SERVICE CHARGES REF : number` → NAME: `SERVICE CHARGES`, MEMO: `PAY REF : number` - Fallback: full description as NAME, type code only as MEMO The NAME/MEMO split enables Odoo reconciliation models to match on: - **Label** (Contains) - clean payee for partner matching - **Note** (Contains) - Lloyds type code for transaction filtering - **Transaction Type** - OFX TRNTYPE for broad categorisation Example rules: | Label Contains | Note Contains | Action | |---|---|---| | `Non-GBP` | | Counterpart: bank charges account | | `DIRECT LINE` | `DD` | Partner: Direct Line | | | `FPI` | Amount Type: Received | | `HMRC` | `FPO` | Partner: HMRC | - Add missing TRNTYPE mappings: CD, CPT, CHQ, BP, CR, DEP, FEE - Extract business logic into testable functions: `extract_payee()`, `parse_amount()`, `determine_trntype()`, `clean_sort_code()` - Set `account_id` once from first record instead of every row - Add FPO to faster payment handling (was only FPI/BGC) Tested against live Lloyds business account statements covering card purchases, FX transactions, faster payments, direct debits, and service charges. OFX output verified importing cleanly into Odoo 18 with correct NAME/MEMO split enabling label-based auto-reconciliation.
- Added overview, features, installation, configuration, and usage sections for the ofxstatement-lloyds plugin. - Explained transaction parsing methods and Odoo reconciliation compatibility.
|
Can you merge this in, and re-publish to the pipi library please |
|
Would you like to add me as a co-maintainer so I can publish further updates as required? Details here: https://pypi.org/manage/project/ofxstatement-lloyds/collaboration/ |
|
Hello, StuartJMackintosh |
|
Can you give me your Pypi username, please? |
Update CSV and tests for statement parsing - Expanded sample-statement.csv with more transaction entries. - Updated test_sample.py to reflect changed and added entries, increasing line count validation. - Verified new fields in statement: currency, account_id, start/end balance and dates. - Ensured accurate assertions for each new transaction data in tests. ```
|
Updated tests and extended test data |
yes, will do (once I have registered...) |
|
pypi: sjmackintosh |
|
Hello. I have sent you invitation for collaboration in Pypi |
|
Thank you! accepted. I will get the update published. |
|
Can you merge this PR? |
- Bumped version to 1.0.2.dev0 - No other changes made to dependencies or entry points.
|
or add me as maintainer to this repo so I can merge etc |
|
No rush - I have pushed update to Pypi already so we can get this synced whenever you are ready. |
|
I will merge it when program will work properly. Can you fix the Mypy problem here?https://github.com/Metasaura/ofxstatement-lloyds/actions/runs/21872704332/job/63140491365?pr=1 |
- Updated `start_date` and `end_date` to use `Optional[datetime.datetime]`. - Improved type hinting for better clarity and type checking.
|
Updated - can you check again. No rush - I have pushed update to Pypi already so we can get this synced whenever you are ready. |
|
Hello, thank you. I had your update checked |
|
I installed the tests locally. seems it was a formatting issue, tests now pass. Hopefully it will go through this time |
|
Congratulations! Your program check was successful this time. I hope there won't be any problems with it further down the road ;) |
Problem
The plugin maps Lloyds CSV descriptions to
sline.memoonly,producing OFX output without a
<NAME>element. Downstreamimporters use NAME as the primary transaction label, so:
: descriptionwith a leading colonNAME is empty (see Bank Statement Line accepts empty string as meeting required=true requirement odoo/odoo#33104)
Solution
Parse Lloyds description text per transaction type to extract a
clean payee name for NAME, with the structured remainder as MEMO.
The Lloyds transaction type code (DD, FPI, FPO, DEB etc.) is
prefixed to the MEMO field, making it available for reconciliation
rule matching via the Note condition. This preserves the
Lloyds-specific codes that are lost in OFX TRNTYPE mapping
(e.g. FPI and BGC both become CREDIT).
Supported patterns:
MERCHANT [ref] [CURRENCY] amount VISAXR rate CD nnnn→ NAME:
MERCHANT, MEMO:DEB amount VISAXR rate CD nnnnNON-GBP TRANS FEE n.nn% CD nnnn→ NAME:
Non-GBP Transaction Fee, MEMO:DEB 2.75% CD 1417MERCHANT CD nnnn [date]→ NAME:
MERCHANT, MEMO:DEB CD nnnnPAYEE ref sortcode ddMMMYY HH:MM→ NAME:
PAYEE, MEMO:FPI ref sortcode ddMMMYY HH:MM→ NAME:
PAYEE, MEMO:FPO ref sortcode ddMMMYY HH:MMPAYEE mandate-ref→ NAME:
PAYEE, MEMO:DD mandate-refSERVICE CHARGES REF : number→ NAME:
SERVICE CHARGES, MEMO:PAY REF : numberReconciliation model usage
The NAME/MEMO split enables Odoo reconciliation models to match on:
Example rules:
Non-GBPDIRECT LINEDDFPIHMRCFPOOther changes
extract_payee(),parse_amount(),determine_trntype(),clean_sort_code()account_idonce from first record instead of every rowTesting
Tested against live Lloyds business account statements covering
card purchases, FX transactions, faster payments, direct debits,
and service charges. OFX output verified importing cleanly into
Odoo 18 with correct NAME/MEMO split enabling label-based
auto-reconciliation.