Sale Product Catalog Extended
sale_product_catalog_extended · OCA/sale-workflow
-
Security25/25No findings
-
Activity25/25Human commit this month
-
Required by5/250 modules depend on it
-
Maturity5/25In 1 Odoo series since 18.0
Heuristic over the facts below, not an audit · How it's computed
Migration considerations
SaleCatalogProductExclusion— Migrating to 19.0: `_sql_constraints` is ignored and its constraints are silently not created: declare `models.Constraint` attributes instead. migration-sql-constraints · source
Migration review checklist, not a compatibility verdict. "Migrating to X.0" applies once you upgrade to that version; "Since X.0" means this version already ignores or rejects that code. Methodology
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
Code analysis
Extracted from the source by best-effort static analysis (no code is executed); details may be incomplete.
Views touched 5
| XML ID | Name | Model | Type | Status |
|---|---|---|---|---|
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) | Handler | Auth | Type | Methods | Flags |
|---|---|---|---|---|---|
/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
-
catalog_history_partnerSelectionsearch='_search_catalog_history_partner'selection=[('delivery_address', 'Delivery address')]store=False -
catalog_last_salesSelectionsearch='_search_catalog_last_sales'selection=[('last_sales', 'Last sales')]store=False -
catalog_origin_dataSelectionsearch='_search_catalog_origin_data'selection=[]store=False -
catalog_price_modeSelectionsearch='_search_catalog_price_mode'selection=[('last_price', 'Last sale')]store=False
-
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
-
catalog_last_order_daysIntegerconfig_parameter='sale_product_catalog_extended.catalog_last_order_days'default=180help='Days of sale history used by the last sales option and the last sale price.'string='Catalog last sales days' -
catalog_last_order_limitIntegerconfig_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_partnerBooleanconfig_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_partnerSelectiondefault_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_salesSelectiondefault_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_dataSelectiondefault_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_modeSelectiondefault_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'
No public methods.
-
partner_idMany2one → res.partnercomodel_name='res.partner'index=Trueondelete='cascade'required=True -
product_idMany2one → product.productcomodel_name='product.product'index=Trueondelete='cascade'required=True
No public methods.
No new fields.
Public methods (1)-
action_confirm(self)
No new fields.
Public methods (3)-
create(self, vals_list)@api.model_create_multi -
default_get(self, fields_list)@api.modelStart 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)