Skip to main content
iVentureTeam

loyalty_one2many

The Rules and Rewards blocks on an Odoo loyalty program form look custom, but loyalty_one2many is just the standard x2many widget wearing a different template: a heading with the field label and an always present Add button.

Siddharth JambukiyaSiddharth JambukiyaOdoo Techno-Functional Consultant
August 24, 2026Updated August 24, 20264 min read
Technical nameloyalty_one2many
Field typesone2many, many2many
Viewsform (loyalty program form, kanban mode sub views)
Moduleloyalty
Used in core3 occurrences in 1 module: the rule and reward lists on the loyalty program form in loyalty
VersionsOdoo 20.0, Odoo 19.0, Odoo 18.0, Odoo 17.0, Odoo 16.0
No-code setupNo. Applied via the widget attribute in view XML
Alternativesone2many, many2many, section_and_note_text

What the Loyalty list widget does

The loyalty_one2many widget renders the Rules and Rewards sections of a loyalty program form: the conditional rules that earn points and the rewards points can buy. Under the hood it is a thirteen line file: a component extending the standard X2ManyField with a replacement template, and a descriptor spreading the standard x2ManyField unchanged.

The template inherit does one thing: where the base x2many shows its control panel buttons, this widget renders an <h4> carrying the field's label, then the button area with a single secondary Add button wired to the standard add flow. That is why each block on the program form reads as a titled card with its own Add action even though the field itself has nolabel="1".

What this means for your team

For marketing and sales teams the payoff is readability: a loyalty program is really two lists, what earns points and what spends them, and this widget gives each list a heading and an unmissable Add button inside the form body. Program managers add buy X get Y rules, promo code conditions or gift card rewards without hunting for the tiny inline add link a plain kanban sub view would offer.

Because the descriptor is the stock x2many, administrators keep all the usual control: crud options can forbid deleting rules on running programs, and record rules apply unchanged. The widget adds presentation, not policy.

Supported options in Odoo 19

No options of its own. The spread of the standard x2many descriptor means the full crud option set applies, with the same subtleties as the base widget: values may be booleans or domains evaluated against the parent record, and sub view arch attributes combine with them.

OptionTypeWhat it does
createboolean or domainInherited from x2many. Allows or forbids creating sub records; a domain is evaluated against the parent record. Gates what the Add button can do.
deleteboolean or domainInherited from x2many. Controls removing sub records, boolean or parent evaluated domain.
linkboolean or domainInherited from x2many. Controls linking existing records where the relation allows it.
unlinkboolean or domainInherited from x2many. Controls detaching records without deleting them.
writeboolean or domainInherited from x2many. New gating in 19: controls whether sub records open editable.(since Odoo 19.0)
The Add button bypasses nothing: create permission and the create option are still enforced by the inherited onAdd flow. Hiding creation via options also hides this button's effect, not the button itself.

Working examples

<!-- Core usage on the loyalty program form (loyalty module) -->
<field name="rule_ids" colspan="2" mode="kanban" nolabel="1" add-label="Add a rule"
       class="o_loyalty_kanban_inline" widget="loyalty_one2many"
       context="{'currency_symbol': currency_symbol, 'program_type': program_type}"/>

The context keys are consumed by the rule and reward sub views and dialogs, which adapt wording and defaults to the program type; the widget itself passes them through untouched.

A thirteen line widget that has not changed since Odoo 16

The interesting engineering fact is how little there is. The registration has survived four major versions with only cosmetic edits: Odoo 16 registered the bare component class, 17 switched to the descriptor spread pattern, 18 reformatted the class body, and 19 dropped the module pragma. No behavioral line has changed since 16, making this one of the most stable custom widgets in core.

One detail worth knowing when restyling: the heading uses the field's string, so relabeling the field in the view (or via Studio's label edit on the field) renames the card heading too. And since the template only replaces the control panel buttons block, everything else, pager, kanban quick add, dialog flows, is rendered by the base x2many machinery documented on our one2many page.

Version compatibility

VersionStatusNotes
Odoo 20.0In developmentNot released. The development branch file is byte-identical to 19.0; see below.
Odoo 19.0VerifiedVerified against the shipped source. Identical behavior to 18.0.
Odoo 18.0VerifiedCosmetic class body reformat only.
Odoo 17.0VerifiedSwitched to the descriptor spread registration pattern; same behavior.
Odoo 16.0VerifiedOriginal version, registered the component class directly.
Stable since 16.0. Upgrades are a non event for this widget; test the surrounding loyalty views instead.

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 development branch file is byte-identical to Odoo 19.0: no new options, no template change, no rename. Whatever Odoo 20 changes in loyalty, it is not this widget. We re-verify after the release.

Common problems and fixes

SymptomCause and fix
The Add button says Add instead of the add-label textThe control panel button caption is hardcoded in the loyalty template; add-label only feeds the inline kanban add link. Override the loyalty.LoyaltyX2ManyField template in a custom module if the caption must change.
The heading shows the wrong titleThe h4 renders the field's label string, which a view or Studio relabel changes. Set the desired string attribute on the field element in the view.
Add button visible but clicking does nothing for some usersCreate access on loyalty.rule or loyalty.reward is denied, or a create option domain evaluates false for this parent. Check access rights and the options dict on the field; the button honors both.

Loyalty list widget vs the alternatives

WidgetBest forKey difference
loyalty_one2manyRule and reward lists on loyalty program formsStock x2many plus a heading and an always visible Add button
one2manyAny standard sub record listDefault control panel, label rendered by the form layout instead of the widget
many2manyLinking existing records rather than owning themLink and unlink semantics, Add picks existing records
section_and_note_textStructured document lines with sections and notesLine styling machinery for account style tables, not kanban cards

Reach for loyalty_one2many outside loyalty only if you want exactly its heading plus Add layout; otherwise the base widgets below are the standard choices.

Frequently asked questions

Is loyalty_one2many different from the normal one2many widget?+
Only in presentation. It spreads the standard x2many descriptor and swaps one template block, adding an h4 heading with the field label and an Add button where the control panel buttons normally sit.
Which fields use loyalty_one2many in core Odoo?+
The rule and reward one2many fields on loyalty.program, rendered in kanban mode on the program form. That covers promotions, coupons, gift cards and eWallet programs, which all share the model.
Can I reuse loyalty_one2many on my own model?+
Yes. It works on any one2many or many2many, on any model, since the loyalty specific part is purely the template. You get the heading plus Add layout wherever you apply it.
Why does my Add a rule label not appear on the button?+
The template hardcodes the caption Add. The add-label attribute you see in core views feeds the inline kanban add link inside the list, not the control panel button.

Loyalty programs that need more than the defaults?

Tiered rewards, partner specific promotions and PoS synced gift cards all start as rule and reward lines behind this widget. We design and build loyalty mechanics across Odoo Sales, Website and Point of Sale, including the custom widgets when the defaults stop fitting.

Plan your loyalty setup with us

How this page was produced

The source, all thirteen lines of loyalty_control_panel_widget.js, was read on Odoo 19.0 together with the loyalty.LoyaltyX2ManyField template inherit in the loyalty module and the program form XML that applies it. The 16.0, 17.0 and 18.0 files were diffed to confirm the widget is behaviorally frozen, and the Odoo 20 statement comes from a diff against the public development branch. Corrections are welcome via our contact page.