Skip to main content
iVentureTeam

so_line_create_button

On a billable project task, the Sales Order Item field carries a small plus button. That is so_line_create_button: a many2one that can spawn a whole sales order in a dialog and wire the task to its first service line automatically.

Siddharth JambukiyaSiddharth JambukiyaOdoo Techno-Functional Consultant
August 24, 2026Updated August 24, 20264 min read
Technical nameso_line_create_button
Field typesmany2one (sale.order.line)
Viewsform (project task and timesheet related forms)
Modulesale_project
Used in core3 occurrences across 2 modules: project task forms in sale_project and sale_timesheet
VersionsOdoo 20.0, Odoo 19.0
No-code setupNo. Applied via the widget attribute in view XML
Alternativesso_line_field, many2one, x2many_buttons

What the SO Line Create button does

The so_line_create_button widget upgrades the Sales Order Item field on project tasks. Rendered normally, it is a plain many2one over sale.order.line. Its addition is a small plus link next to the input that appears only while the record is editable and sale_line_id is still empty.

Clicking the plus opens a form dialog titled Create Sales Order on sale.order, not on the line. When the user saves the new order, the widget calls the server method get_first_service_line on it and writes the returned line into the task's sale_line_id. The user never picks a line manually; the first service line of the fresh order is wired in automatically.

What this means for your team

This widget exists for the services flow where delivery starts before sales paperwork: a project manager creates tasks, work begins, and only later does someone need an order to bill against. Instead of leaving the task, creating an order in Sales, finding the right line and coming back, the whole loop happens in one dialog from the task form. Timesheets on the task then bill against the linked line.

The context defaults are deliberate: the new order is preset to the task's company or the user's active company, the current user becomes the salesperson, and the PDF quote builder pane is hidden because the dialog exists to mint a billable line, not to design a quote document.

Supported options in Odoo 19

The widget is a thin wrapper over the standard many2one descriptor, so the whole many2one option set applies, including the two undocumented knobs that only exist in extractProps. It declares no options of its own; the plus button is unconditional behavior.

OptionTypeWhat it does
no_openbooleanInherited from many2one. Removes the internal link that opens the linked sale order line's form.
no_createbooleanInherited from many2one. Disables creating order lines from the autocomplete. Does not affect the plus button, which creates an order, not a line, through its own dialog.
no_quick_createbooleanInherited from many2one. Removes the type-to-create shortcut in the autocomplete while keeping the create and edit dialog.
no_create_editbooleanInherited from many2one. Removes the create and edit dialog from the autocomplete.
search_thresholdintegerInherited from many2one, new in 19.0. Minimum typed characters before the line search runs.(since Odoo 19.0)
placeholder_fieldfield nameInherited from many2one, new in 19.0. Char field on the task whose value becomes the placeholder text.(since Odoo 19.0)
can_scan_barcodebooleanInherited and undocumented: read in the many2one extractProps only. Enables barcode based lookup on mobile.
create_name_fieldfield nameInherited and undocumented: read in the many2one extractProps only. Redirects typed text on quick create to another field.
The plus button cannot be disabled by an option. It hides itself only when the record is readonly or once sale_line_id is set. To suppress it entirely, use the plain many2one widget instead.

Working examples

<!-- Core usage on the project task form (sale_project module) -->
<field name="sale_line_id"
       widget="so_line_create_button"
       placeholder="Non-billable"
       context="{'so_form_view_ref': 'sale.view_order_form', 'dialog_size': 'large'}"/>

The so_form_view_ref context key is how the caller controls which sale order form the dialog shows; the widget passes it through as form_view_ref. The placeholder Non-billable is the core touch that tells users an empty field is a valid state.

The first service line contract and the naming quirk

The write back is worth reading closely. get_first_service_line is called on sale.order after the dialog saves and returns a list of line ids; the widget writes the first one into sale_line_id. If the order the user built contains no service products, there is no service line to link, and the task keeps an empty field even though an order now exists, a surprise worth training teams on.

Two packaging quirks: the component file ships in sale_project, but its QWeb template is named sale_timesheet.SoLineCreateButton, a leftover from where the widget was first drafted. And because the descriptor comes from buildM2OFieldDescription, everything a many2one can do, barcode scanning, typeahead thresholds, dynamic placeholders, works here even though none of it is used in core views.

Version compatibility

VersionStatusNotes
Odoo 20.0In developmentNot released. The file moves to the new sale_service module on the development branch; see below.
Odoo 19.0VerifiedIntroduced here. Verified against the shipped sale_project source.
Odoo 18.0Not availableDoes not exist. sale_line_id used a plain many2one.
Odoo 17.0Not availableDoes not exist.
Odoo 16.0Not availableDoes not exist.
New in Odoo 19. On 18 and earlier the task form used a plain many2one for sale_line_id and orders had to be created in the Sales app.

What is changing in Odoo 20

Odoo 20 is expected at Odoo Experience in Brussels, 24 to 26 September 2026. The changes below are read from the public development branch and are not final until release.

The file moves modules: on the development branch it lives in sale_service, part of a restructuring of the sale and project bridge modules, and it is migrated to the new props system. Behavior, the dialog context and the first service line write back are unchanged. Custom modules importing it from @sale_project paths will need their imports updated. We re-verify after the release.

Common problems and fixes

SymptomCause and fix
The plus button is not visibleThe record is readonly, or sale_line_id already holds a value; the button renders only for editable empty fields. Clear the field or make the record editable. There is no option to force the button.
The order was created but the task field stayed emptyget_first_service_line found no service line: the order built in the dialog contains no service products. Add at least one service product to the order, then set the Sales Order Item manually, or recreate the order with a service line.
The dialog opens the wrong sales order form layoutThe so_form_view_ref context key on the field decides which form view the dialog loads. Pass the intended view's XML id in so_form_view_ref, as the core task form does.
Widget missing after an upgrade to Odoo 20The component moved from sale_project to the sale_service module on the development branch. Update custom imports and asset bundles to the new module path once Odoo 20 ships.

SO Line Create button vs the alternatives

WidgetBest forKey difference
so_line_create_buttonLinking a task to a billable order line, creating the order on the spotPlus button opens a sale order dialog and auto links the first service line
so_line_fieldReferencing an existing order line with edit trackingFlags the record as edited on change instead of creating orders
many2oneA plain reference to an order lineNo creation flow beyond the standard quick create
x2many_buttonsJumping to a handful of related documentsRenders links to existing records, creates nothing

Use this widget only for the create and link flow. If tasks should merely reference existing order lines, or you need edit tracking, the alternatives below fit better.

Frequently asked questions

What exactly does the plus button on the Sales Order Item field create?+
A complete sales order, via a form dialog on sale.order. After the save, the widget fetches the order's first service line with get_first_service_line and writes that line into the task's sale_line_id.
Why is the new order's salesperson me?+
The dialog context presets default_user_id to the current user and the company to the task's company or your active company. Both can be changed inside the dialog before saving.
Can I use so_line_create_button on my own model?+
Yes, on any many2one to sale.order.line, but the write back is hardcoded to a field named sale_line_id, so the receiving field must have exactly that name on the record the widget sits on.
Is so_line_create_button available on Odoo 18?+
No. It is new in Odoo 19. On 18 the task form shows a plain many2one and orders must be created separately.

Billing services from projects still a copy paste job?

Task to order linking, timesheet billing rules and service products that invoice correctly need the sale, project and timesheet apps wired together properly. We implement end to end services billing on Odoo, from quote templates to the exact widgets your PMs click.

Automate your services billing

How this page was produced

Behavior was read from so_line_create_button.js and its template in the Odoo 19.0 sale_project module: the plus button visibility condition, the dialog context keys, and the get_first_service_line write back. Absence in 16.0 through 18.0 was confirmed against those branch trees, and the module move was read from the public development branch tree. Found an inaccuracy? Tell us via our contact page.