Skip to main content
iVentureTeam

button_new_contract

A button that asks for a start date, checks twice that the date is legitimate, then creates the contract and loads it.

Siddharth JambukiyaSiddharth JambukiyaOdoo Techno-Functional Consultant
August 27, 2026Updated August 29, 20264 min read
Technical namebutton_new_contract
Viewsform (view widget, <widget> element)
Modulehr, the Employees app
Used in coreThe employee form in hr
VersionsOdoo 20.0, Odoo 19.0
No-code setupNo. It is set in view XML and depends on module-specific data
Alternativesversions_timeline, work_permit_upload, hr_department_chart

What the new contract button does

An employee's terms change over time, and Odoo models that as versions: a new contract is a new version starting on a date, with the previous one closing before it.

Creating one is therefore not a simple record creation. The previous version has to be in a state that allows closing, and the new date must not collide with a contract that already covers it.

This widget wraps both checks around a date picker. Click, and it saves and asks whether the current version is finished; pick a date, and it asks whether that date is free; only then does it create the contract and load it.

What this means for your team

Overlapping contracts are one of the more expensive HR data errors, because payroll consumes them and the mistake surfaces as a payment. Two checks before creation, both server side, is a proportionate amount of caution.

The design point worth borrowing is where the rules live. Contract validity is a Python concern, and the widget's job is only to ask at the right moments. Any customization to those rules belongs on the model, not here.

Supported options in Odoo 19

The widget declares no options and takes the standard view widget props. The two server checks and the picker configuration are listed below. Read from the new contract button source, Odoo 19.0.

OptionTypeWhat it does
check_contract_finishedserver check on the versionAsked before the picker opens, about the version being replaced. Raises rather than returning.(since Odoo 19.0)
check_no_existing_contractserver check on the employeeAsked after a date is chosen, about that date. Raises rather than returning.(since Odoo 19.0)
version_idcontext key on reloadThe newly created version, added to the search context so the form shows the new contract.(since Odoo 19.0)
the picker typefixed to dateA contract starts on a day, so there is no time component.(default: date)(since Odoo 19.0)

The two checks happen at different moments. The first runs before the picker opens and looks at the current version. The second runs after a date is chosen and looks at that date. Neither is repeated.

Working examples

Placing it

<widget name="button_new_contract"/>

No attributes. It reads the employee and version from the record.

The sequence

save -> check current version finished
     -> pick a date
     -> check no existing contract on it
     -> create -> reload with the new version

Two checks, both server side.

The reload context

{ ...search context, version_id: new id }

Which is what makes the form show the new contract.

Two checks that only exist to raise

The reload at the end is the part worth understanding, because it is not a plain refresh.

After creating the contract the widget saves again, then reloads the model with the existing search context plus the new version identifier. That extra context key is what tells the employee form which version to display, so the user lands on the contract they just created rather than back on the old one.

The two checks are ordinary server calls whose only purpose is to raise. Neither returns a value the widget uses: if the rule is violated the call raises and the sequence stops with the server's own message, which is why there is no error handling in the file.

The picker is configured as date only and its apply handler guards against an empty date, so dismissing the picker does nothing rather than attempting a creation with no date.

One nuance in the first check: it is asked about the current version identifier, not the employee. That is deliberate, because the question is whether the version being replaced can be closed.

Version compatibility

VersionStatusNotes
Odoo 20.0Partial / changedNot released. Adds a guard suppressing an end-date dialog during the save.
Odoo 19.0VerifiedFirst version. Verified against the shipped source.
Odoo 18.0Not availableWidget does not exist.
Odoo 17.0Not availableWidget does not exist.
Odoo 16.0Not availableWidget does not exist.

Upgrade note. The widget is new in Odoo 19 alongside the version-based contract model. Databases upgrading from the older contract model gain this flow with the standard views.

What is changing in Odoo 20

Odoo 20 is expected at Odoo Experience in Brussels, 24 to 26 September 2026. The development branch is unstable and this may still change; we re-verify this page after the release.

A guard around the save. The development branch sets a flag on the record before saving and clears it afterwards, which suppresses a contract end-date dialog that would otherwise interrupt the sequence. The picker target also moves to a reference rather than a fixed identifier.

Common problems and fixes

SymptomCause and fix
An error before the picker opensThe current version is not in a state that allows closing. Close or correct the existing contract first.
An error after choosing a dateA contract already covers that date. Pick a date after the existing contract ends.
Dismissing the picker does nothingThe apply handler guards against an empty date. Expected.
The form still shows the old contractThe reload adds the new version to the context; something overrode it. Reload the employee form manually.
An end-date dialog interrupts the saveFixed on the development branch with a flag around the save. Complete the dialog and retry on Odoo 19.
The widget is missingThe employees module is not installed in that database. Install Employees.

New contract button vs the alternatives

WidgetBest forKey difference
button_new_contractCreating a dated employee contract with its validity checked firstTwo server-side checks at different moments, then a reload scoped to the new version
versions_timelineA document's earlier versionsFile history rather than contract creation
work_permit_uploadThe work permit documentAn upload rather than a record action
hr_department_chartSeeing the org structureA chart rather than an action

Creating the version record directly through a relation field skips both checks, which is faster and unsafe. The button exists precisely because the checks are the point.

Frequently asked questions

Why are there two checks?+
They ask different questions at different moments: whether the version being replaced can be closed, and whether the chosen date is already covered by a contract.
Why is there no error handling?+
Both checks exist only to raise. When a rule is violated the server call raises with its own message and the sequence stops there.
Why does the form reload?+
The reload adds the new version identifier to the search context, which is what makes the employee form display the contract that was just created.
Can I pick a time as well as a date?+
No. The picker is configured as date only, because a contract starts on a day.
Does it change in Odoo 20?+
The development branch adds a flag that suppresses a contract end-date dialog during the save, and moves the picker target to a reference.

HR data your payroll can trust

Contract versions, effective dates and payroll inputs have to agree, and an overlap is only visible once someone is paid wrong. We implement Odoo HR and payroll integration, on versions 16 through 19.

Book a free consultation

How this page was produced

The save then finished-version check before the picker, the existing-contract check after the date is chosen, the creation call, the reload with the new version in context and the date only picker with its empty date guard were read from the new contract button source on the Odoo 19.0 branch. Version coverage comes from the absence of the file on 16.0, 17.0 and 18.0, and a comparison against the public development branch. Spotted an error? Tell us and we will correct the page.