Skip to content

Request: Loan & Lease management module for Odoo 20 Community #209

Closed

Description

@7kulk37

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

  1. odoomates commented on Oct 31, 2026

    @odoomates
    Owner

    Thanks for the clear request and the careful comparison: it made the scope easy to set. We built it: om_account_loan for Odoo 20 Community, free (LGPL-3), in draft pull request #210, ready for your testing on staging.

    What it covers (your list)

    • Contract: lender, principal, currency, start and first payment dates, number of payments, monthly / quarterly / semi-annual / annual payments, fixed or floating rate (dated rate changes), accounts (long-term, short-term, interest) and journals; company defaults in Accounting settings.
    • Schedule: annuity or fixed principal, or imported from the lender's CSV / Excel file; interest per period or on actual days / 365; due dates in calendar months (31 Jan, 28/29 Feb, 31 Mar); rounding residue on the last line; unpaid lines editable, paid lines locked.
    • Drawdown in one or more tranches: Dr Bank / Cr Loan; the unpaid schedule follows the principal actually drawn.
    • Payment by schedule line: Dr Loan + Dr Interest / Cr Bank; partial and early repayment with interest to the date, then a lower instalment or a shorter term.
    • Current / non-current reclassification at a period end (adjusting the earlier ones).
    • Report (Reporting > Management > Loans): outstanding principal, interest accrued, next due date and amount, due within / after 12 months, as list, pivot and PDF; each loan also prints with its schedule.
    • Withholding tax on the interest: set a tax with a negative amount on the loan (e.g. -1% for PND 53): it is deducted from the payment to the lender and booked as a tax line, and shown per instalment and in the report.
    • Lease mode: the lease liability at the present value of the payments, recognised against the right-of-use asset; each payment comes as the lessor's vendor bill split into the liability reduction and the interest (by a button, for selected instalments or by a daily job, posted or draft). With our Assets app installed, om_account_loan_asset installs 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

    git clone -b 20.0-om_account_loan https://github.com/odoomates/odooapps.git
    

    Install om_account_loan (and om_account_asset for 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.

  2. 7kulk37 commented on Nov 1, 2026

    @7kulk37
    Author

    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 tests check 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_loan
    Commit: 0557e0a04ac9b3c624b6c0ae53f809f0093f74a7
    PR: #210
    Lab: /opt/odoo/loan-lab/loan20, port 8073, DBs loan20_test, loan20_tests, loan20_th
    Main instance on 8069: untouched (303), separate containers/volumes.

    1. Install gate

    om_account_loan alone on a clean DB:

    INSTALL_EXIT=0
    

    Installed state: installed, Odoo module version 20.0.1.0.0.
    With om_account_asset, om_account_loan_asset auto-installs (installed).

    Install warnings produced by the module (the PR's tests check is red at step Install and test, exit 1; the CI log is not public without auth, so I cannot attribute the red check solely to these warnings):

    WARNING account.loan.line.loan_type: selection attribute will be ignored as the field is related
    WARNING Two fields (withholding, withholding_tax_id) of account.loan.pay() have the same label: Withholding Tax.
    WARNING Two fields (withholding, withholding_tax_id) of account.loan.repay() have the same label: Withholding Tax.
    

    Source:

    • om_account_loan/models/account_loan_line.py:26
    • om_account_loan/wizard/account_loan_pay.py:25-26
    • om_account_loan/wizard/account_loan_repay.py:25-26

    2. Vendor test suite

    Command: -i om_account_loan,om_account_asset --test-enable --test-tags /om_account_loan,/om_account_loan_asset.

    1 failed, 16 error(s) of 79 tests when loading database 'loan20_tests'
    

    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:

    TypeError: account.loan.import.file: use BinaryValue instead of bytes
      at tests/common.py:97
    

    Product, with a valid base64 string (as the web client sends):

    File ".../wizard/account_loan_import.py", line 74, in _read_rows
        content = base64.b64decode(self.file or b'')
    binascii.Error: Invalid base64-encoded string: number of data characters (81) cannot be 1 more than a multiple of 4
    

    Cause: Odoo 20 binary fields return BinaryValue (BinaryBytes), not a base64 str.
    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) or BinaryBytes(content).

    2.2 Lease posted-bill cancellation — product bug

    UserError: The Bill/Refund date is required to validate this document.
      at models/account_loan_line.py:296
      -> models/account_move.py:57 -> account/models/account_move.py:5932
    

    Cause: reversing an in_invoice with cancel=True passes only date; Odoo 20 requires invoice_date on the refund.
    Fix: in _reverse_moves, for an invoice move set values.setdefault('invoice_date', move.invoice_date or move.date).
    Proved in a runtime patch: action_cancel_payment() then succeeds; bill payment_state = reversed.

    Draft bills cancel correctly (test_draft_bills passes).

    2.3 ROU asset test — time-dependent assertion

    AssertionError: 'close' != 'open'
    

    The test lease starts 2025-01-01 and ends 2026-01-01; at today's date (2026-11-01) om_account_asset has closed it. With a current lease the asset is created correctly:

    ROU True open 11677.03 11677.03 2026-11-01 2027-10-31
    

    The feature works; the test needs a current date or an explicit close expectation for a past term.

    Continued in the next comment.

  3. 7kulk37 commented on Nov 1, 2026

    @7kulk37
    Author

    Part 2/3 — continued from the previous comment.

    3. Baseline (independent probes)

    3.1 Baseline: 100,000, 12 months, 0.5%/month, fixed principal

    Synthetic reproduction of the numbers in this thread; no real bank statement was supplied.

    FIXED_PRINCIPAL LINES 12 TOTAL 103250.0 PRINCIPAL 100000.0 INTEREST 3250.0 LAST_PRINCIPAL 8333.37 LAST_AMOUNT 8375.04
    DRAW_ENTRY [('101403', 100000.0, 0.0), ('214952', 0.0, 100000.0)]
    PAY1_ENTRY [('101404', 0.0, 8833.33), ('214952', 8333.33, 0.0), ('612951', 500.0, 0.0)]
    STATE closed MOVES 13 BAL_LT 0.0 BAL_ST 0 BAL_INT 3250.0 BAL_OUT -103250.0 OUTSTANDING 0.0
    

    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

    ANNUITY LINES 12 TOTAL 103279.73 PRINCIPAL 100000.0 INTEREST 3279.73 LAST_PRINCIPAL 8563.87 LAST_AMOUNT 8606.69
    PAY1_ENTRY [('101404', 0.0, 8606.64), ('214952', 8106.64, 0.0), ('612951', 500.0, 0.0)]
    STATE closed MOVES 13 BAL_LT -0.0 BAL_ST 0 BAL_INT 3279.73 BAL_OUT -103279.73 OUTSTANDING 0.0
    

    4. Feature probes

    Feature Result
    Tranches 60k + 40k line 2 opening 95,136.01, interest 375.68, amount 8,910.35; sum principal 100,000; outstanding 95,136.01
    Early repayment 20k after 3 payments interest 176.30; line 4 opening 55,558.28, amount 6,328.50; count 12; sum principal 80,000
    Reclassification 24m 31 Jan: Dr LT 48,504.17 / Cr ST 48,504.17; after 3 payments + 30 Apr: ST 49,235.37, LT 38,909.37, sum 88,144.74 = outstanding
    Floating rate 6% → 8% from 1 Jul lines 1-6 unchanged; line 7 interest 338.32, amount 8,656.46; remove rate: 253.74 / 8,606.65; sum 100,000
    Partial instalment (principal 4,000) last principal 12,666.70; sum 100,000; outstanding 87,666.67
    WHT -1% (generic chart) line 1 WHT 5.00, net 8,828.33; Dr LT 8,333.33 + Dr interest 500 / Cr WHT 5.00 / Cr outstanding 8,828.33; tax base 500; report withheld 5.00
    Thai chart th / THB company TH/THB, 198 accounts; same WHT entry: Cr 111205 8,828.33, Cr 211100 5.00, Dr 221100 8,333.33, Dr 611100 500.00. Probe used 211100 for both short-term loan and WHT payable; use a dedicated WHT account in production.
    Lease 12 × 1,000 at 6% PV 11,618.93; first bill 941.91 principal + 58.09 interest; VAT 7% + WHT 1% → total 1,069.42 (vendor tests)
    ROU asset current lease state open, value 11,677.03, term 2026-11-01 → 2027-10-31
    PDF loan 29,160 bytes %PDF, report 13,686 bytes %PDF; wkhtmltopdf ContentNotFoundError warning but file rendered

    5. UI

    • http://172.16.60.17:8073, DB loan20_test, login admin.
    • Menus: Invoicing/Accounting > Loans > Loans / Leases / Instalments / Reclassification, Invoicing/Reporting > Management > Loans.
    • Loan form: statusbar (Closed / Running / Draft), Early Repayment, Compute Schedule, 12-line schedule with totals, Pay buttons, Operations/Accounting/Notes tabs, chatter.
    • Pay wizard: Mar 1 2025, principal 8,333.33, interest 458.33, total 8,791.66; paid line 2, outstanding 83,333.34, next Apr 1, 8,750.00.
    • Report form: At/Type/Loans, View and Print PDF; View shows LOAN/2025/0007, outstanding 83,333.34, next Apr 1 2025, 8,750.00, due within 12 months 83,333.34, due after 0.
    • A core web_tour clipboard error appears on this HTTP lab (navigator.clipboard undefined); it also appears on Discuss before opening Loans, so it is environment noise, not a loan-module defect. Lab-only; HTTPS or no web_tour avoids it.

    6. Claim matrix

    Claim Verdict Evidence
    Contract fields PASS UI form, probes
    Annuity / fixed principal / calendar months / residue PASS 3.1, 3.2
    Drawdown in tranches PASS 4
    Payment split principal/interest PASS 3.1
    Partial and early repayment PASS 4 (partial instalment, early 20k)
    Current/non-current reclassification PASS 4
    Report + PDF PASS 4, 5
    WHT on interest (PND 53 booking) PASS 4 (generic + Thai chart)
    Lease + lessor bills + VAT/WHT PASS 4
    ROU asset PASS (current lease) 4, 2.3
    CSV/XLSX import FAIL 2.1
    Cancel posted lease bill FAIL 2.2
    Multi-currency PASS (vendor test; no revaluation) test suite
    Approval workflow Not implemented —
    Thai translation Not included (i18n/th.po absent) —
    PND 53 filing/report Not implemented (books the tax only) —
    CI green FAIL 3 module warnings + 17 test failures

    Continued in the next comment.

  4. 7kulk37 commented on Nov 1, 2026

    @7kulk37
    Author

    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:

    1. CSV/XLSX import: base64.b64decode(self.file) → self.file.content (plus fix the tests to pass a base64 string).
    2. Cancel posted lease bill: add invoice_date to the reversal values.
    3. Fix the 3 install warnings so their own CI gate can pass.
    4. Make the ROU test use a current lease.

    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) — the 1 failed, 16 error(s) of 79 tests summary, the import BinaryValue error, the lease Bill/Refund date error, and the ROU 'close' != 'open' assertion:

    Raw test log excerpt

    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:

    Loan report PDF

    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:

    Loan position report PDF

    The web_tour clipboard error noted in section 5 is a core Odoo 20 issue on plain HTTP (navigator.clipboard is 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.

  5. 7kulk37 commented on Nov 1, 2026

    @7kulk37
    Author

    Summary of the three comments above — findings and what I need

    We tested om_account_loan at 0557e0a on 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) but self.file is a BinaryValue; use self.file.content, and make the tests send a base64 string; (2) cancelling a posted lease bill fails because the reversal has no invoice_date. There are also three install warnings and a date-dependent ROU test.

    What I need from you:

    1. A fix commit or tag covering the two bugs, the warnings, and the ROU test.
    2. Green CI on that commit.
    3. Confirmation of the import contract and posted-lease cancellation behavior.
    4. Which missing items are in scope: approval workflow, Thai translation, PND 53 filing, multi-currency revaluation.

    I will re-run the lab on the fixed commit and report the result.

  6. odoomates commented on Nov 1, 2026

    @odoomates
    Owner

    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

    aa8253e on #210 (20.0-om_account_loan), followed by 73b403c (a test assertion) and 3147384 (wording only):

    • Import: the wizard reads the file from its binary value (self.file.content), as Odoo 20 binary fields hold the content, not base64. The tests send a base64 string, as the web client does.
    • Cancelling a posted lease bill: the credit note gets the bill date (invoice_date), so it posts. The test now also checks the credit note's date and state.
    • Install warnings: all three are gone. The related loan_type no longer repeats its selection, and the tax of the pay and repay wizards is labelled Withholding Tax Rule.
    • ROU asset test: it runs on the start of the lease (2025-01-01), so it no longer depends on today's date. With the term over, the asset is closed, as you saw, which is the expected behaviour.
    • Any country: the module is not tied to a country. The withholding tax is any tax of the company with a negative amount, on its own account and tax grids, so it works with any chart of accounts. 3147384 removes the Thai example from the field help and the README.

    2. CI

    Green on aa8253e, 73b403c and 3147384: 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):

    • a CSV or XLSX file, one row per instalment; a first row of titles is skipped;
    • three columns: Date, Principal, Interest or Date, Instalment, Interest (chosen in the wizard);
    • CSV separated by commas, semicolons or tabs; decimal comma or point; dates as YYYY-MM-DD, DD/MM/YYYY, DD.MM.YYYY, DD-MM-YYYY or the user's date format;
    • checked before anything is written: due dates after the start (or the last payment) and increasing, no negative interest, and the principal adding up to what is left to repay. Errors are listed by row;
    • paid instalments stay; a new import replaces the unpaid lines only.

    Cancelling the last bill of a lease:

    • a draft bill is cancelled;
    • a posted, unpaid bill is reversed by a credit note at the bill date: the bill becomes Reversed and the instalment is to bill again;
    • a paid bill is refused: remove its payment first.

    4. Scope

    • Thai translation: just before merging, once the strings are final, as they can still change. We will share the .pot then, and your th.po is very welcome.
    • Approval workflow: no extra module. If you need it, install Approvals (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.
    • PND 53 filing: specific to Thailand, so not in the loan module; we can discuss it later, separately. The loan already books the withholding as a normal tax line on the account of the tax (with its tax grids), so a Thai withholding report can read it like the withholding on vendor bills.
    • Multi-currency revaluation: it applies to every foreign currency balance, not only loans, so it is done by our generic om_currency_revaluation module. 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 ContentNotFoundError of wkhtmltopdf

    It 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 else web.base.url), all three render with no warning. Setting report.url to 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.

  7. 7kulk37 commented on Nov 1, 2026

    @7kulk37
    Author

    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 the ContentNotFoundError was my lab's unreachable report.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:

    IMPORT1 3 [('2025-02-01', 30000.0, 500.0), ('2025-03-01', 30000.0, 350.0), ('2025-04-01', 40000.0, 200.0)]
    PAY1_ENTRY [('101404', 0.0, 30500.0), ('214962', 30000.0, 0.0), ('612961', 500.0, 0.0)]
    

    After paying line 1, re-importing 20k/20k/30k kept the posted line:

    IMPORT2 4 SEQ [1, 2, 3, 4] STATE ['posted', 'draft', 'draft', 'draft']
    PRINCIPAL [30000.0, 20000.0, 20000.0, 30000.0] COUNT 4 OUT 70000.0
    BEFORE_PAID REFUSED: UserError: Row 1: the first instalment must be due after 2025-02-01.
    

    No binascii/BinaryValue error. Root cause confirmed: self.file is a BinaryValue; .content is 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

    POSTED_BILL in_invoice posted not_paid 2025-02-01
    CANCEL_POSTED bill posted reversed refund in_refund posted 2025-02-01
                  bill_date 2025-02-01 line draft line_move False outstanding 11618.93
    DRAFT_BILL in_invoice draft -> CANCEL_DRAFT bill cancel line draft
    PAID_BILL_AFTER posted paid -> CANCEL_PAID REFUSED:
      UserError: The bill BILL/2025/02/0002 (LEASE/2025/0010 - Lease payment 1) is paid: remove its payment first.
    

    The credit note has the bill's invoice_date, the original bill is payment_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_type warning and no duplicate Withholding Tax labels; the only warning is the unrelated markdown2 warning from mail. Module state installed, version 20.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:

    ROU_CURRENT True open  11677.03 11677.03 2026-11-01 2027-10-31
    ROU_PAST    True close 11618.93     0.00 2025-01-01 2025-12-31
    

    So 'close' != 'open' was a date-dependent assertion; the product behavior is correct. Agreed.

    5. CI

    The GitHub check tests is success on 3147384 (and on aa8253e, 73b403c) via the check-runs API. Locally the module suite is 0 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 module

    With report.url=http://127.0.0.1:1: ContentNotFoundError, PDF still 28,547 bytes. With report.url=http://odoo20:8069 (reachable): the same 28,547-byte PDF, no warning. web.base.url was http://localhost:8069 inside a one-off shell container that cannot reach it. I will set report.url in 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_approval or om_currency_revaluation. A tag on 3147384 (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

  8. mehjabinfarsana commented on Nov 1, 2026

    @mehjabinfarsana
    Collaborator

    Thanks @7kulk37 for bringing this topic again, along with this its good to link the loan app with cash forecast also

  9. odoomates commented on Nov 1, 2026

    @odoomates
    Owner

    @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 3147384 we 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, head e0f5620d.

    Fixes

    • Protected schedule: a paid instalment, a posted operation or a loan entry is changed by cancelling it on the loan only, not from Accounting nor through the API. The lender and the loan accounts are fixed once the loan has entries, its terms once it runs.
    • Lock dates: an entry dated in a locked period is refused with the lock date, instead of being posted on a later date than its schedule.
    • Foreign currency: a loan or lease repaid at other rates than its drawdown realizes the exchange difference on each repayment (Exchange Difference entry, to the exchange gain or loss account). Repaid in full, the liability is back to zero in the company currency too.
    • Payments: dated from the start of the loan and the previous payment, paid once the loan is drawn down, no negative amounts.
    • Lease bills: a draft bill is posted only while it still matches its lease payment. In journals using documents (Latin America), the bill is left in draft for the lessor's document number.
    • Withholding at payment (the Withhold taxes, e.g. Thailand and India): on a lease, Odoo withholds them when the bill is paid; the schedule and the report no longer count them at the bill.

    Added

    • Cash forecast: with Cash Forecast installed, the bridge om_account_loan_cash_forecast installs 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.
    • Monthly reclassification: a setting, Reclassify the Loans Monthly: the running loans and leases are reclassified at each month end without the wizard.
    • Loans Analysis (Reporting > Management): principal, interest and instalments year by year, pivot and graph.
    • Roles: the accountants (Show Full Accounting Features) run the loans; the administrators alone delete them and set the defaults.
    • Easier to use:
      • Pay and Bill only on the next instalment;
      • the instalments due within 30 days by date;
      • the instalment shown in the pay wizard;
      • the early repayment starts at zero;
      • lease wording on the leases;
      • the payments, bills, reclassifications and rate changes in the chatter;
      • the report totals in the company currency.

    Re-test

    e0f5620d pins 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:

    1. a sanitized real bank schedule, imported or computed;
    2. the Thai scenario with your WHT tax: on a loan instalment, and on a lease bill paid with Register Payment;
    3. a loan in a foreign currency through to full repayment.

    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 .pot here once the re-test is through, for your th.po.

  10. odoomates commented on Nov 2, 2026

    @odoomates
    Owner

    @7kulk37 would you like to have a final look before merging ?

  11. 7kulk37 commented on Nov 2, 2026

    @7kulk37
    Author

    dear @odoomates

    I tested the core om_account_loan at e0f5620d and 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.

  12. odoomates commented on Nov 2, 2026

    @odoomates
    Owner

    @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 after e0f5620d, so your tests did not cover them:

    • the rate, the rate type and the number of payments of a running loan are now locked;
    • a new rate is a dated rate change, on fixed-rate loans too (refused on leases);
    • a new term is an early repayment;
    • the reclassifications are listed in the Operations tab.

    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.po is welcome.

    Closing this request as done with #210. Thank you for the detailed reports, they shaped much of this module.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions