Skip to content

[19.0][IMP] contract: UX revamp, last_date_invoiced & demo data#1427

Open
bosd wants to merge 5 commits into
OCA:19.0from
bosd:19.0-imp-contract
Open

[19.0][IMP] contract: UX revamp, last_date_invoiced & demo data#1427
bosd wants to merge 5 commits into
OCA:19.0from
bosd:19.0-imp-contract

Conversation

@bosd

@bosd bosd commented May 7, 2026

Copy link
Copy Markdown
Contributor

Core, low-risk UX improvements to the contract module. Originally a larger PR — now split into focused PRs (per @pedrobaeza) so the clear changes can merge independently from the ones that need more discussion.

This PR (core):

  • last_date_invoiced computed/displayed on contract.contract
  • form / list / search / kanban view revamp (activities, group-bys, Analytic Account label, Other-Info layout)
  • date_end after date_start validation
  • demo data (running / expired / upcoming contracts + template + tags)
  • module icon refresh

Split out into separate PRs:

@bosd bosd force-pushed the 19.0-imp-contract branch 2 times, most recently from 3d05d15 to 811976b Compare May 8, 2026 07:25
@bosd bosd changed the title [19.0][IMP] contract [19.0][IMP] contract UX ❤️ May 8, 2026
@bosd bosd force-pushed the 19.0-imp-contract branch from 811976b to 457c2a0 Compare May 8, 2026 07:38
@bosd

bosd commented May 8, 2026

Copy link
Copy Markdown
Contributor Author

info block pdf renders correctly now in bubule layout
image

@bosd bosd force-pushed the 19.0-imp-contract branch from 457c2a0 to 2e6ab46 Compare May 8, 2026 08:05
@bosd

bosd commented May 8, 2026

Copy link
Copy Markdown
Contributor Author
image

Apply correct headings tags, address widget.
Updated smartbutton icon, so it is aligned with what odoo core uses.

@bosd

bosd commented May 10, 2026

Copy link
Copy Markdown
Contributor Author

Robust recurring-invoice cron — client context

Pushed two commits (a8c88773, e33a2676) that harden the recurring-invoice cron and surface failures per contract in the UI.

The problem

We hit this on a multi-company production deployment with a few hundred active recurring contracts. One contract had a bad data entry that made _prepare_invoice raise during the cron run. Because the upstream cron processes all of a company's contracts in a single batched account.move.create([...]), the SQL transaction rolled back the whole batch — no contracts at all got invoiced for that company on that day.

The painful part for the client wasn't just the missed invoicing run, it was finding the bad apple. There's no per-contract error trail. The cron log shows one stack trace (without naming the offending contract clearly) and there's no in-UI marker. Their bookkeeper had to scan hundreds of contracts manually to figure out which one was tripping the cron.

What this PR adds

  • Two-tier execution:
    • Fast path — one batched account.move.create([...]) per company (identical to the previous behaviour and performance).
    • On failure — fall back to per-contract processing inside cr.savepoint() so a single contract with bad data does not block its company batch and SQL-level errors don't poison the transaction for the rest.
  • Per-contract failure trail:
    • New stored fields invoice_generation_error (Text), invoice_generation_error_date (Datetime), has_invoice_generation_error (Boolean).
    • Invoice Generation Failed filter in the contract search view — one click and you have the bad apples.
    • Orange fa-exclamation-triangle icon at the start of the row in the contract list, plus decoration-warning row tint, so the failed contracts are visible at a glance even without filtering.
    • Form-view warning banner with the error message, date, and a Dismiss button so the responsible user can clear it after fixing.
    • Chatter post + TODO activity assigned to the contract's responsible user. Both are de-duplicated so consecutive cron runs against persistent bad data don't spam.
  • Auto-clear on recovery: the next successful cron run for that contract clears the error fields and resolves the activity.

Why per-contract savepoints (not just a per-contract try/except)

We started with a plain try/except per contract and the client was happy. But it only catches Python-level errors before the cursor flushes. If the failure is SQL-level (FK violation, unique constraint, check constraint), PostgreSQL marks the transaction aborted; every subsequent contract in the loop then fails with current transaction is aborted. The cr.savepoint() context manager issues SAVEPOINT / ROLLBACK TO SAVEPOINT, isolating each contract's writes properly.

Tests

Six new test cases in test_contract.py:

  • one bad contract is isolated; the healthy ones still get invoiced
  • error fields and activity are populated on failure
  • a successful retry clears the flag and resolves the activity
  • no duplicate chatter / activity on consecutive failures
  • healthy batches still hit the single-call fast path (verified by spying on _recurring_create_invoice)
  • Dismiss action clears the flag without running the cron

Full contract suite: 75 tests, 0 failures, 0 errors locally. Pre-commit: clean.

@bosd bosd force-pushed the 19.0-imp-contract branch from a5090ac to 5dbff29 Compare May 30, 2026 23:48
@bosd bosd force-pushed the 19.0-imp-contract branch from 5dbff29 to 8d94763 Compare June 11, 2026 06:49
@pedrobaeza

Copy link
Copy Markdown
Member

21 commits?

@bosd bosd force-pushed the 19.0-imp-contract branch from 8d94763 to 5c7bbc3 Compare June 11, 2026 07:04
@bosd

bosd commented Jun 11, 2026

Copy link
Copy Markdown
Contributor Author

21 commits?

Dropped it to 9 now 😄

@bosd bosd marked this pull request as ready for review June 11, 2026 07:07
@pedrobaeza

Copy link
Copy Markdown
Member

Well, still too many, specially for discussing about each one. Seeing for example the archived products one, why do you need that? Isn't better to remove the active_test context key?

@bosd bosd force-pushed the 19.0-imp-contract branch from 5c7bbc3 to 66169aa Compare June 11, 2026 07:30
@bosd

bosd commented Jun 11, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for the review @pedrobaeza!

On the archived-products domain: the active_test: False context on contract_line_ids can't simply be removed — it was added in d25115d ("No contract line and invoices when contract is archived") so that an archived contract's lines stay visible and processable. That context leaks into the embedded product picker, which is what surfaces archived products there. Because a view-level domain attribute replaces the model field domain (they don't AND together), each customer/supplier line view has to re-assert ('active', '=', True). If you'd rather re-assert active_test: True on the product field instead of the domain, I'm happy to switch — I'd just want to confirm the context-merge precedence on runboat first.

On the commit count: I've kept it at 9, with each one an atomic, self-contained unit that reviews independently: last_date_invoiced, view/UX revamp, archived-product fix, date validation, PDF report, portal page, demo data, cron hardening, icon. None depend on another's internals, so they can be discussed — or dropped — one by one. Glad to drop any you consider out of scope for this PR.

Also pushed a small test (test_action_view_invoice_generation_error) so codecov/project is green again.

@pedrobaeza

Copy link
Copy Markdown
Member

I was talking about splitting this into several PRs, for merging clear things, and discuss the rest, instead of having to block everything until all are agreed.

bosd added 5 commits June 11, 2026 09:57
Aggregate the latest invoiced date from the contract lines into a stored
computed field on contract.contract, label it explicitly in the views, and
bump the manifest version.
Add a kanban view and enable the activity view, improve the list and search
view UX, add a partner search group-by, refine the form layout (Other
Information in a single two-column grid, 'Analytic Account' label) and
streamline the contract.tag UX.
@bosd bosd changed the title [19.0][IMP] contract UX ❤️ [19.0][IMP] contract: UX revamp, last_date_invoiced & demo data Jun 11, 2026
@bosd

bosd commented Jun 11, 2026

Copy link
Copy Markdown
Contributor Author

@pedrobaeza split done 👍 — broke this into focused PRs. This one now holds just the core, low-risk UX changes; the rest are independent so the clear ones can merge without waiting on the others:

They only share contract.py/contract.xml/tests, which rebase cleanly as they merge one by one.

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants