Repository navigation
Request: Loan & Lease management module for Odoo 20 Community #209
Description
Module
new module — om_account_loan (loan & lease management)
Odoo version
20.0
The business need
We use your accounting suite on Odoo 20 Community (20.0-20261015) for a small business, and we would like to ask you to consider building a Loan & Lease management module for it.
This is a genuine need for us, not a nice-to-have. Today a bank loan is 13 manual journal entries with the amortization schedule kept in a spreadsheet, and lease payments are handled as vendor bills. That is fragile, hard to audit, and does not scale as our borrowing grows. Odoo 20 Enterprise has native Loans; CE has nothing comparable, and your repo has no loan module. A maintained module from you would close a real gap for us, and we believe for other CE users too.
The solution you would like
What we would need:
- contract: lender, principal, currency, dates, fixed or floating rate, payment frequency, accounts and journal;
- schedule: annuity, fixed principal, or import; calendar-month dates; editable while unposted; rounding residue on the last line;
- drawdown, in one or more tranches: Dr Bank / Cr Loan;
- payment by schedule line: Dr Loan + Dr Interest / Cr Bank; partial and early repayment;
- current/non-current reclassification at each period end;
- outstanding principal, accrued interest and due-date report, with PDF;
- for Thailand: an optional WHT line on the interest portion (1%, PND 53);
- lease mode: schedule plus purchase invoices (the OCA pattern), optionally a right-of-use asset.
We would be grateful if you would consider building and maintaining om_account_loan for 20.0, free and alongside the accounting suite.
Alternatives
We tested the two installable references before asking:
- OCA account_loan (AGPL-3, 18.0 only): the most complete free engine — loans and leases, amortization, APR/EAR, rate changes, early repayment. On Odoo 18 its test suite passes, and the schedule, reclassification and early repayment behave correctly. Its weakness is the cash leg — drawdown and repayments go through partner accounts, so the bank posting is manual.
- aos_company_bank_loan (LGPL-3, 19.0): the right bank workflow and the right entries (Dr Bank / Cr Loan; Dr Loan + Dr Interest / Cr Bank), but it does not install on current 19 without a code change, and its schedule uses 30-day months rather than calendar months.
We also looked at a couple more related modules (employee-loan and lending-focused), but we have not tested them fully enough to recommend them.
Other information
We will test the module on staging with real bank data, report with command and UI evidence as we did on #206, and contribute Thai translation and WHT scenarios. We are also happy to help with acceptance tests and feedback during development.
Activity
[ADD] om_account_loan: leases, withholding, import
odoomates commentedon Oct 31, 2026
Thanks for the clear request and the careful comparison: it made the scope easy to set. We built it:
om_account_loanfor Odoo 20 Community, free (LGPL-3), in draft pull request #210, ready for your testing on staging.What it covers (your list)
om_account_loan_assetinstalls by itself and creates the right-of-use asset, depreciated over the lease term.One design point to check with your bank workflow: the bank leg posts to the bank journal's outstanding receipts / payments account, as Odoo payments do, so the bank statement line reconciles with it. If you post without statement imports, set Post Bank Leg On = Bank Account on the loan to post straight to the bank account.
How to test
Install
om_account_loan(andom_account_assetfor the right-of-use asset). The demo data has two loans (floating rate in two tranches; quarterly fixed principal on actual days) and an office lease with its bills.The pull request is still a draft: CI is running on the latest commit and we may still push fixes there; you will see them on #210. We would be grateful for the same kind of testing as on #206: entries on real bank data, the reclassification at your period ends, the PND 53 scenario, and anything that does not match how you book loans today. Your Thai translation is very welcome too, once the strings settle. Feedback here or on #210, whichever you prefer.
7kulk37 commentedon Nov 1, 2026
Replying to @odoomates's comment in this thread: #209 (comment)
Thanks for publishing the module and the draft PR. We tested the branch independently on a clean Odoo 20 CE lab. This is the full report, not a summary. Bottom line: the core engine works, but two real bugs block the promised import and lease-cancellation flows; the vendor suite is 1 failed + 16 errors, and the PR's
testscheck is red. Do not adopt yet.The 100,000 / 12 months / 0.5% per month case below is a synthetic reproduction of the numbers described in this thread; no real bank statement was supplied. The module stores the rate as an annual rate, so 0.5%/month is shown as 6.0% annual.
om_account_loan on Odoo 20 CE — test report
Date: 2026-11-01
Host:
stg-odoo20(172.16.60.17)Odoo:
20.0-20261015(odoo:20.0)Branch:
20.0-om_account_loanCommit:
0557e0a04ac9b3c624b6c0ae53f809f0093f74a7PR: #210
Lab:
/opt/odoo/loan-lab/loan20, port 8073, DBsloan20_test,loan20_tests,loan20_thMain instance on 8069: untouched (
303), separate containers/volumes.1. Install gate
om_account_loanalone on a clean DB:Installed state:
installed, Odoo module version20.0.1.0.0.With
om_account_asset,om_account_loan_assetauto-installs (installed).Install warnings produced by the module (the PR's
testscheck is red at stepInstall and test, exit 1; the CI log is not public without auth, so I cannot attribute the red check solely to these warnings):Source:
om_account_loan/models/account_loan_line.py:26om_account_loan/wizard/account_loan_pay.py:25-26om_account_loan/wizard/account_loan_repay.py:25-262. Vendor test suite
Command:
-i om_account_loan,om_account_asset --test-enable --test-tags /om_account_loan,/om_account_loan_asset.Passing: schedule maths, drawdown/payment entries, tranches, early repayment, floating rate, reclassification, withholding, lease recognition/bills/taxes, report, access, multi-company.
Failing: import (15 errors), lease posted-bill cancellation (1 error), ROU asset assertion (1 fail).
2.1 Import — product bug + test-harness bug
Test harness:
Product, with a valid base64 string (as the web client sends):
Cause: Odoo 20 binary fields return
BinaryValue(BinaryBytes), not a base64str.Fix:
content = self.file.content if self.file else b''.Proved in a runtime patch: CSV import then yields 3 lines (30,000 / 30,000 / 40,000 principal; 500 / 350 / 200 interest) and the payment entry is correct.
The tests also need
'file': base64.b64encode(content).decode()(str) orBinaryBytes(content).2.2 Lease posted-bill cancellation — product bug
Cause: reversing an
in_invoicewithcancel=Truepasses onlydate; Odoo 20 requiresinvoice_dateon the refund.Fix: in
_reverse_moves, for an invoice move setvalues.setdefault('invoice_date', move.invoice_date or move.date).Proved in a runtime patch:
action_cancel_payment()then succeeds; billpayment_state = reversed.Draft bills cancel correctly (
test_draft_billspasses).2.3 ROU asset test — time-dependent assertion
The test lease starts 2025-01-01 and ends 2026-01-01; at today's date (2026-11-01)
om_account_assethas closed it. With a current lease the asset is created correctly:The feature works; the test needs a current date or an explicit
closeexpectation for a past term.Continued in the next comment.
7kulk37 commentedon Nov 1, 2026
Part 2/3 — continued from the previous comment.
3. Baseline (independent probes)
3.1 Baseline: 100,000, 12 months, 0.5%/month, fixed principal
Dates are calendar months: 2025-02-01, 2025-03-01, ... 2026-01-01. Line 12 principal 8,333.37, interest 41.67.
3.2 Vendor reference: 100,000, 6%, 12 months, annuity
4. Feature probes
th/ THB%PDF, report 13,686 bytes%PDF; wkhtmltopdfContentNotFoundErrorwarning but file rendered5. UI
http://172.16.60.17:8073, DBloan20_test, loginadmin.web_tourclipboard error appears on this HTTP lab (navigator.clipboardundefined); it also appears on Discuss before opening Loans, so it is environment noise, not a loan-module defect. Lab-only; HTTPS or noweb_touravoids it.6. Claim matrix
i18n/th.poabsent)Continued in the next comment.
7kulk37 commentedon Nov 1, 2026
Part 3/3 — continued from the previous comment.
7. Recommendation
Do not adopt yet. The core engine is good — schedule, entries, tranches, early repayment, reclass, WHT, lease, ROU, report all work on 20.0. Two real bugs block the promised scope:
base64.b64decode(self.file)→self.file.content(plus fix the tests to pass a base64 string).invoice_dateto the reversal values.After a fix commit, re-run this lab (install + tests + these probes), then test a sanitized real bank schedule and the Thai PND 53 scenario.
Raw logs and probe outputs are in the lab (
loan20_tests.log,probe_*.out,loan20_install.log); I can paste any specific section or full traceback on request.Screenshots
1. Raw test log (selected lines, exact text from
loan20_tests.log) — the1 failed, 16 error(s) of 79 testssummary, the importBinaryValueerror, the leaseBill/Refund dateerror, and the ROU'close' != 'open'assertion:2. Loan report PDF, page 1 — LOAN/2025/0007, 100,000 at 6.0% annual (= 0.5%/month), fixed principal, 12 lines, total 103,250.00, interest 3,250.00, outstanding 83,333.34 after 2 payments:
3. Loans and leases position report PDF, page 1 — same loan; outstanding 83,333.34; due within 12 months 83,333.34; due after 12 months 0.00:
The
web_tourclipboard error noted in section 5 is a core Odoo 20 issue on plain HTTP (navigator.clipboardis undefined), not a loan-module defect. It prevented a clean live-form screenshot on this lab; the PDFs above and the shell/probe outputs are from the same database.7kulk37 commentedon Nov 1, 2026
Summary of the three comments above — findings and what I need
We tested
om_account_loanat0557e0aon Odoo 20 CE. The detail is in the three comments above.Found: install passes. The core engine passes my probes: annuity, fixed-principal and calendar-month schedules, drawdown and payment entries, tranches, partial and early repayment, reclassification, WHT, lease bills, ROU asset, and report/PDF. The 100,000 / 12 months / 0.5% per month baseline gives 103,250.00 total and 3,250.00 interest.
Blocking: the vendor suite is 1 failed + 16 errors of 79. Two real bugs: (1) import calls
base64.b64decode(self.file)butself.fileis aBinaryValue; useself.file.content, and make the tests send a base64 string; (2) cancelling a posted lease bill fails because the reversal has noinvoice_date. There are also three install warnings and a date-dependent ROU test.What I need from you:
I will re-run the lab on the fixed commit and report the result.
[FIX] om_account_loan: import file, refund of a lease bill, warnings
odoomates commentedon Nov 1, 2026
Thank you for the thorough report: every point was reproducible and the causes were exactly right. Our CI showed the same 17 failures on
0557e0a. Here is the follow-up on your four questions.1. Fix commit
aa8253eon #210 (20.0-om_account_loan), followed by73b403c(a test assertion) and3147384(wording only):self.file.content), as Odoo 20 binary fields hold the content, not base64. The tests send a base64 string, as the web client does.invoice_date), so it posts. The test now also checks the credit note's date and state.loan_typeno longer repeats its selection, and the tax of the pay and repay wizards is labelled Withholding Tax Rule.3147384removes the Thai example from the field help and the README.2. CI
Green on
aa8253e,73b403cand3147384: 0 failed, 0 errors of 1200 tests, with no warning from the module.3. Import and cancellation behaviour
Import (Imported schedule method, then Import Schedule):
YYYY-MM-DD,DD/MM/YYYY,DD.MM.YYYY,DD-MM-YYYYor the user's date format;Cancelling the last bill of a lease:
4. Scope
.potthen, and yourth.pois very welcome.om_approval) and add a flow on the loan buttons you want approved (Confirm, Pay, Early Repayment), with the approvers and the amounts you choose.om_currency_revaluationmodule. The loan entries carry their amount in the loan currency, so the loan accounts are revalued at the closing rate with the other balances.The
ContentNotFoundErrorof wkhtmltopdfIt comes from the lab, not the reports. The loan PDFs use only the standard Odoo layouts and load no file of their own. We rendered the loan, the loan report and a core invoice: with no server reachable, the loan and the invoice both warn, and with one at the URL wkhtmltopdf uses (
report.url, or elseweb.base.url), all three render with no warning. Settingreport.urlto an address the Odoo container can reach usually removes it.Your re-run of the lab on
3147384, and then the real bank schedule, would be very welcome. Feedback here or on #210.7kulk37 commentedon Nov 1, 2026
Replying to @odoomates's follow-up.
First, my apologies for two earlier errors on my side: the ROU
'close' != 'open'was my test's date, and theContentNotFoundErrorwas my lab's unreachablereport.url; I should have verified both before reporting them. Thank you for the fast, precise fixes and the clear follow-up — the turnaround on the two P1s was excellent.Retested on
3147384(PR head) in a fresh Odoo 20.0-20261015 lab. The two code fixes hold; the two points that were not module bugs are confirmed as such. Exact results:1. Import — fixed
Fresh DB, wizard created with
file=base64.b64encode(csv).decode()(the web-client contract), 3 rows:After paying line 1, re-importing 20k/20k/30k kept the posted line:
No
binascii/BinaryValueerror. Root cause confirmed:self.fileis aBinaryValue;.contentis the content. Your tests now send the same base64 string as the web client. Your CSV/XLSX/semicolon/decimal-comma tests also pass in the 79-test module suite.2. Lease bill cancellation — fixed
The credit note has the bill's
invoice_date, the original bill ispayment_state=reversed, and the line is back to draft. This matches your description exactly.3. Install warnings — gone
Fresh install log has no
account.loan.line.loan_typewarning and no duplicateWithholding Taxlabels; the only warning is the unrelatedmarkdown2warning frommail. Module stateinstalled, version20.0.1.0.0.4. ROU — my earlier failure was the test date, not the module
Your
freeze_time('2025-01-01')test passes. Independent leases:So
'close' != 'open'was a date-dependent assertion; the product behavior is correct. Agreed.5. CI
The GitHub check
testsissuccesson3147384(and onaa8253e,73b403c) via the check-runs API. Locally the module suite is0 failed, 0 error(s) of 79 tests. I did not re-run the full 1,200-test CI suite locally; the green check is the CI evidence.6.
ContentNotFoundError— lab, not moduleWith
report.url=http://127.0.0.1:1:ContentNotFoundError, PDF still 28,547 bytes. Withreport.url=http://odoo20:8069(reachable): the same 28,547-byte PDF, no warning.web.base.urlwashttp://localhost:8069inside a one-off shell container that cannot reach it. I will setreport.urlin the lab; agreed.7. WHT
The generic-chart probe still passes: 12 lines, interest 3,250.00, WHT 32.50, line 1 WHT 5.00, tax line
Cr 219999 5.00, report withheld 5.00. The latest diff is help/README only; I did not re-run the Thai chart in this pass.Status
I see no remaining reproducible module bug in the tested scope; the two P1s are fixed. I did not test a real bank schedule (none supplied; the baseline is synthetic), and I did not test
om_approvalorom_currency_revaluation. A tag on3147384(or a merge) would let me pin the re-test. Thai translation and PND 53 remain scope items, not blockers from my side.No further fix is required from my side.
CASE CLOSED
mehjabinfarsana commentedon Nov 1, 2026
Thanks @7kulk37 for bringing this topic again, along with this its good to link the loan app with cash forecast also
odoomates commentedon Nov 1, 2026
@7kulk37 thank you for the re-test, and no apology needed: both points were worth checking, and the evidence made them quick to settle.
@mehjabinfarsana good point: the loans and leases are now in the cash forecast too (see below).
Since
3147384we ran a wider QA round on the module (forms, security, 13 charts of accounts, foreign currencies) and added what came out of it. Everything is on #210, heade0f5620d.Fixes
Added
om_account_loan_cash_forecastinstalls by itself. The unpaid instalments (net of the tax withheld) and the lease payments not yet billed (with their taxes) are expected on their due dates.Re-test
e0f5620dpins the re-test. As we write, CI is still running on it: it may come back green or red, and we will come back here with the result (and a fix if needed). Most useful now:One note on the menu: Loans sits in Accounting next to Assets, as our other accounting apps, so a user needs Show Full Accounting Features to see it (given to every accountant by Odoo 20 Accounting Community).
Thai translation: the strings are settling with this round; we will share the
.pothere once the re-test is through, for yourth.po.[ADD] om_account_loan: loans
[ADD] om_account_loan: leases, withholding, import
[FIX] om_account_loan: import file, refund of a lease bill, warnings
[ADD] om_account_loan: loans and leases
[ADD] om_account_loan: loans and leases
[ADD] om_account_loan: loans and leases
odoomates commentedon Nov 2, 2026
@7kulk37 would you like to have a final look before merging ?
7kulk37 commentedon Nov 2, 2026
dear @odoomates
I tested the core
om_account_loanate0f5620dand found no issues in my test cases. The install was clean, the vendor suite passed on my test cases, and my probes covered import, posted lease-bill cancellation, foreign-currency repayment, schedule protection, lock dates, payment validation, and Thai WHT. My schedule is still synthetic; I do not have a sanitized real bank schedule.I have to be honest about my limits: my test cases are limited, and my understanding of the additional features — Cash Forecast, monthly reclassification, and Loans Analysis — is also limited. I did not request those features, and I do not know their expected results or how they should integrate with the core modules. I only did a simple click-around as a non-owner accountant: the menus, loan/lease forms, Cash Forecast screen, and Loans Analysis screen loaded, and I saw no visible error. I did not test the monthly-reclassification setting deeply. That was only a smoke test, not acceptance. I am sorry I could not test those features more deeply.
So my final look covers the core module only: no blocker from my side. I cannot sign off the extra features. If you want them accepted, please define their expected behaviour and integration and have the owner of those requirements test them.
From my side, the core loan module is ready for merge.
odoomates commentedon Nov 2, 2026
@7kulk37 thank you for the final look, and for being clear about what it covers. That is exactly what we needed.
Your reply and the merge crossed: #210 was merged into 20.0 before your comment, as
dd7ae9d4. It also has a few changes made aftere0f5620d, so your tests did not cover them:If you have time, a re-test of the rate changes on 20.0 would be welcome, ideally with a real bank schedule if you ever get a sanitized one. If you find anything, please open a new issue.
You did more than enough on Cash Forecast, monthly reclassification and Loans Analysis, thank you. We will take care of testing those ourselves.
You offered a Thai translation earlier. The strings are now final, so a PR with
om_account_loan/i18n/th.pois welcome.Closing this request as done with #210. Thank you for the detailed reports, they shaped much of this module.