Skip to content

fix: populate OFX NAME field from Lloyds transaction descriptions#1

Merged
Metasaura merged 9 commits intoMetasaura:mainfrom
OpenDigitalCC:main
Feb 10, 2026
Merged

fix: populate OFX NAME field from Lloyds transaction descriptions#1
Metasaura merged 9 commits intoMetasaura:mainfrom
OpenDigitalCC:main

Conversation

@StuartJMackintosh
Copy link

Problem

The plugin maps Lloyds CSV descriptions to sline.memo only,
producing OFX output without a <NAME> element. Downstream
importers use NAME as the primary transaction label, so:

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:

  • 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

Reconciliation model usage

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

Other changes

  • 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)

Testing

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.

SJM added 2 commits February 9, 2026 19:22
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.
@StuartJMackintosh
Copy link
Author

Can you merge this in, and re-publish to the pipi library please

@StuartJMackintosh
Copy link
Author

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/

@Metasaura
Copy link
Owner

Hello, StuartJMackintosh
Thank you for cooperation
I feel tired today, so I will check your suggestions tomorrow
I am going to try to add you as a co-maintainer

@Metasaura
Copy link
Owner

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.
```
@StuartJMackintosh
Copy link
Author

Updated tests and extended test data

@StuartJMackintosh
Copy link
Author

Can you give me your Pypi username, please?

yes, will do (once I have registered...)

@StuartJMackintosh
Copy link
Author

pypi: sjmackintosh

@Metasaura
Copy link
Owner

Hello. I have sent you invitation for collaboration in Pypi

@StuartJMackintosh
Copy link
Author

Thank you! accepted. I will get the update published.

@StuartJMackintosh
Copy link
Author

Can you merge this PR?

- Bumped version to 1.0.2.dev0
- No other changes made to dependencies or entry points.
@StuartJMackintosh
Copy link
Author

or add me as maintainer to this repo so I can merge etc

@StuartJMackintosh
Copy link
Author

No rush - I have pushed update to Pypi already so we can get this synced whenever you are ready.

@Metasaura
Copy link
Owner

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

SJM added 2 commits February 10, 2026 18:35
- Updated `start_date` and `end_date` to use `Optional[datetime.datetime]`.
- Improved type hinting for better clarity and type checking.
@StuartJMackintosh
Copy link
Author

Updated - can you check again.

No rush - I have pushed update to Pypi already so we can get this synced whenever you are ready.

@Metasaura
Copy link
Owner

Hello, thank you. I had your update checked

```
Refactor regex patterns; tidy up plugin.py

- Improved readability of regex definitions in plugin.py.
- Minor formatting adjustments to lines for better alignment.
- Updated test assertions for clarity in test_sample.py.
```
@StuartJMackintosh
Copy link
Author

I installed the tests locally. seems it was a formatting issue, tests now pass. Hopefully it will go through this time

@Metasaura Metasaura merged commit bd7491d into Metasaura:main Feb 10, 2026
4 checks passed
@Metasaura
Copy link
Owner

Congratulations! Your program check was successful this time. I hope there won't be any problems with it further down the road ;)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants