Skip to content

[18.0][FIX] contract_termination: exclude terminated contracts from the In progress filter - #1499

Open
marcos-mendez wants to merge 1 commit into
OCA:18.0from
marcos-mendez:18.0-fix-contract_termination-search-filter
Open

[18.0][FIX] contract_termination: exclude terminated contracts from the In progress filter#1499
marcos-mendez wants to merge 1 commit into
OCA:18.0from
marcos-mendez:18.0-fix-contract_termination-search-filter

Conversation

@marcos-mendez

Copy link
Copy Markdown

Problem

The contract search view filters running contracts on dates only:

['|', ('date_end', '>=', context_today().strftime('%Y-%m-%d')),
      '&', ('date_end', '=', False), ('recurring_next_date', '!=', False)]

is_terminated is never taken into account. contract_termination adds the field and adapts the form view — buttons, the red termination banner, readonly attributes — but never touches the search view. Both action_customer_contract and action_supplier_contract apply this filter by default through search_default_not_finished, so it is what every user sees when opening the contract list.

The result: a terminated contract keeps being listed as In progress until its end date is reached.

Why this is not an edge case

Termination stops the contract lines at:

max(terminate_date, line.last_date_invoiced)
    if terminate_lines_with_last_date_invoiced and line.last_date_invoiced
    else terminate_date

So whenever a contract is terminated after having been invoiced ahead — and the wizard offers exactly that option — the lines stop at the last invoiced date and date_end, which is computed from the lines, lands in the future by construction. The contract is terminated and sits in the In progress list at the same time.

A contract invoiced one year ahead stays listed as running for a year after termination, and every count, filter or report built on top of that filter is wrong for the whole period. I hit this on a production database: a contract terminated with a full reason and comment kept showing as In progress, and the only way to tell was to open the form and see the red banner.

The data is right; only the list lies. That makes it the kind of bug people work around rather than report.

Solution

Confined to the search view, no contract data touched:

  • add ('is_terminated', '=', False) to the not_finished filter;
  • add a terminated filter next to finished, so terminated contracts can be listed on purpose.

The new filter sits in the same group as In progress and Finished, so it ORs with them like they already OR with each other.

The filter domain is restated rather than composed, because view inheritance cannot AND a condition into an existing domain attribute. If the base domain changes upstream, this override has to follow — the usual cost of position="attributes", and the reason the duplicated part is kept verbatim.

Tests

Three tests added to TestContractTermination. They read the domain from the search view the module actually ships rather than restating it, so a future edit to the filter cannot silently pass the tests:

arch = self.env["contract.contract"].get_view(
    self.env.ref("contract.contract_contract_search_view").id, "search"
)["arch"]
node = etree.fromstring(arch).xpath(f"//filter[@name='{filter_name}']")[0]
return safe_eval(node.get("domain"), {"context_today": ...})
test asserts
test_in_progress_filter_excludes_terminated_contract a terminated contract leaves the In progress filter
test_terminated_filter_lists_terminated_contract the new Terminated filter lists it
test_cancelling_termination_restores_in_progress cancelling the termination puts it back

The first test builds its own contract ending one year in the future, and asserts date_end >= today after terminating. That guard matters: with the 2018 dates of the shared fixture the contract would fall out of the filter on dates alone and the test would pass without exercising the fix at all. As written, the date part of the domain still matches, so only is_terminated can keep the contract out of the list.

Run against Odoo 18.0: 8 tests, 0 failed, 0 errors.

As a negative control the is_terminated condition was removed from the filter and the suite re-run: exactly one test fails, and it is the right one —

FAIL: TestContractTermination.test_in_progress_filter_excludes_terminated_contract
AssertionError: contract.contract(11,) unexpectedly found in contract.contract(11, 7, 8, 9)

The other two keep passing, as they exercise the new filter and the cancellation path, which do not depend on that domain.

pre-commit passes on the full set of modified files.

…progress filter

The contract search view filters running contracts on dates only:

    ['|', ('date_end', '>=', today),
          '&', ('date_end', '=', False), ('recurring_next_date', '!=', False)]

is_terminated is never taken into account, so a terminated contract keeps
being listed as "In progress" until its end date is reached.

This is not an edge case. Terminating a contract stops its lines at
max(terminate_date, last_date_invoiced) when the lines are terminated with
the last invoiced date, so a contract that was invoiced ahead ends up
terminated with date_end in the future by construction. A contract invoiced
one year ahead stays in the "In progress" list for a year after it has been
terminated, and every count or report built on that filter is wrong for the
whole period.

Add ('is_terminated', '=', False) to the filter, and add a "Terminated"
filter next to "Finished" so terminated contracts can be listed on purpose.
The change is confined to the search view: no contract data is touched.
@OCA-git-bot OCA-git-bot added series:18.0 mod:contract_termination Module contract_termination labels Aug 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

mod:contract_termination Module contract_termination series:18.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants