Skip to content
Health
60/100
fair
  • Security25/25
    No findings
  • Activity25/25
    Human commit this month
  • Required by5/25
    0 modules depend on it
  • Maturity5/25
    In 1 Odoo series since 18.0

Heuristic over the facts below, not an audit · How it's computed

Security findings
Grave / minor (static analysis)
Required by
0
Modules depending on it
External deps
0 pip · 0 bin
Python packages / system binaries
License
AGPL-3
No conflicts with its dependencies
Folder size
0.15 MB
Module directory on disk
Code analysis 1 migration note 5 models 5 views 4 HTTP endpoints

Description

This module extends the standard Odoo product catalog available from sale orders with the following additions:

Multi-line product cards

When a product has more than one order line in the current sale order, the catalog renders one card per line instead of a single aggregated card. Each card shows the individual quantity and unit price for that specific line, allowing independent editing without opening the order form.

Per-line actions

Each in-order card exposes three inline actions:

  • New line – adds a new order line for the same product.
  • Edit – opens the specific order line form directly from the catalog.
  • Remove – removes that individual line from the order.

Search panel options

The catalog search panel gets these sections, combinable with each other and with the standard ones:

  • Origin: the cards shown, the products or the ones other modules add (e.g. one card per vendor row with sale_product_catalog_supplierinfo). It is only shown when such a module is installed.
  • Last sales: restricts the cards of the chosen origin to the products previously sold to the customer (last 180 days by default), most frequently sold first, then by delivered quantity.
  • Price: Last sale shows the unit price of the most recent delivered sale to the customer instead of the pricelist price, for the products that have one, and applies it to the lines added from the catalog.
  • History: the partner the sale history is matched against, the customer (commercial partner, including its child contacts) or the order delivery address. It is only shown when enabled in the settings and while the Last sales option or the Last sale price is active, as it has no effect otherwise.

The options preselected when the catalog is opened, the period and the product limit of the last sales are set in the Sales settings (see Configuration).

Exclude from last sales

The card dropdown menu adds an Exclude from last sales entry. It stores the product and the catalog history partner in a dedicated model, so that product is no longer offered by the Last sales option for any order of that partner. The Last sale price is not affected.

The entry is only shown while the Last sales option is active. On the vendor cards of sale_product_catalog_supplierinfo it excludes the product, not the vendor row.

The exclusion is dropped as soon as an order containing that product is confirmed for the same partner, so the product goes back to the Last sales option without any manual clean up. Adding the product to an already confirmed order has the same effect.

The exclusions can be checked and deleted in Sales > Configuration > Catalog Last Sales Exclusions, to offer an excluded product again without selling it.

Image zoom

Clicking on a product image in the catalog opens a full-size zoom dialog.

Dependencies

Odoo dependencies
Python dependencies
None
System dependencies
None
Required by
None

Code analysis

Extracted from the source by best-effort static analysis (no code is executed); details may be incomplete.

Views touched 5

XML IDNameModelTypeStatus
product_view_search_catalog product.product search Inherits product.product_view_search_catalog
res_config_settings_view_form res.config.settings form Inherits sale.res_config_settings_view_form
sale_catalog_product_exclusion_view_list sale.catalog.product.exclusion list New
sale_catalog_product_exclusion_view_search sale.catalog.product.exclusion search New
sale_order_line_view_form_editable sale.order.line form Inherits sale.sale_order_line_view_form_readonly

HTTP endpoints 4

Route(s)HandlerAuthTypeMethodsFlags
/product/catalog/sale/exclude_from_last_sales SaleProductCatalogController.product_catalog_exclude_from_last_sales user json ALL
/product/catalog/sale/get_order_line_data SaleProductCatalogController.product_catalog_get_order_line_data user json ALL
/product/catalog/sale/open_order_line SaleProductCatalogController.product_catalog_open_order_line user json ALL
/product/catalog/sale/update_line_qty SaleProductCatalogController.product_catalog_update_line_qty user json ALL

Models touched 5

New fields (4)
  • catalog_history_partner Selection
    search='_search_catalog_history_partner' selection=[('delivery_address', 'Delivery address')] store=False
  • catalog_last_sales Selection
    search='_search_catalog_last_sales' selection=[('last_sales', 'Last sales')] store=False
  • catalog_origin_data Selection
    search='_search_catalog_origin_data' selection=[] store=False
  • catalog_price_mode Selection
    search='_search_catalog_price_mode' selection=[('last_price', 'Last sale')] store=False
Public methods (4)
  • search_count(self, domain, limit=None)
    @api.model
  • search_fetch(self, domain, field_names, offset=0, limit=None, order=None)
    @api.model
  • search_panel_select_multi_range(self, field_name, **kwargs)
    @api.model
  • search_panel_select_range(self, field_name, **kwargs)
    @api.model

New fields (7)
  • catalog_last_order_days Integer
    config_parameter='sale_product_catalog_extended.catalog_last_order_days' default=180 help='Days of sale history used by the last sales option and the last sale price.' string='Catalog last sales days'
  • catalog_last_order_limit Integer
    config_parameter='sale_product_catalog_extended.catalog_last_order_limit' help='Maximum number of products shown by the last sales option. No limit when 0.' string='Catalog last sales limit'
  • catalog_show_history_partner Boolean
    config_parameter='sale_product_catalog_extended.catalog_show_history_partner' help='Show the History section in the product catalog search panel. When hidden, the history partner default still applies.' string='Show the catalog history partner'
  • default_catalog_history_partner Selection
    default_model='product.product' help='Partner the sale history is matched against by default. The customer (commercial partner) when empty.' selection=_catalog_field_selection('catalog_history_partner') string='Catalog history partner'
  • default_catalog_last_sales Selection
    default_model='product.product' help='Show by default only the products sold to the customer, most frequently sold first.' selection=_catalog_field_selection('catalog_last_sales') string='Catalog last sales'
  • default_catalog_origin_data Selection
    default_model='product.product' help='Cards shown by default in the product catalog of sale orders. Products when empty.' selection=_catalog_field_selection('catalog_origin_data') string='Catalog origin'
  • default_catalog_price_mode Selection
    default_model='product.product' help='Price shown by default in the product catalog. The pricelist price when empty.' selection=_catalog_field_selection('catalog_price_mode') string='Catalog price'
Public methods (0)

No public methods.

New fields (2)
  • partner_id Many2one → res.partner
    comodel_name='res.partner' index=True ondelete='cascade' required=True
  • product_id Many2one → product.product
    comodel_name='product.product' index=True ondelete='cascade' required=True
Public methods (0)

No public methods.

New fields (0)

No new fields.

Public methods (1)
  • action_confirm(self)

New fields (0)

No new fields.

Public methods (3)
  • create(self, vals_list)
    @api.model_create_multi
  • default_get(self, fields_list)
    @api.model
    Start the line opened from a catalog card with the values the catalog sets on the lines it adds (see ``sale.order._get_catalog_new_line_vals``).
  • write(self, vals)