Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 80 additions & 0 deletions sale_product_catalog_extended/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
=============================
Sale Product Catalog Extended
=============================

..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:3249e0d34a64863dab34dadb18eb4d322761bd559ec506bc3ceb92d6efc3f22d
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
:target: https://odoo-community.org/page/development-status
:alt: Beta
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fsale--workflow-lightgray.png?logo=github
:target: https://github.com/OCA/sale-workflow/tree/18.0/sale_product_catalog_extended
:alt: OCA/sale-workflow
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/sale-workflow-18-0/sale-workflow-18-0-sale_product_catalog_extended
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png
:target: https://runboat.odoo-community.org/builds?repo=OCA/sale-workflow&target_branch=18.0
:alt: Try me on Runboat

|badge1| |badge2| |badge3| |badge4| |badge5|

This module extends the product catalog to allow quick editing of lines
without needing to access the sales order.

**Table of contents**

.. contents::
:local:

Bug Tracker
===========

Bugs are tracked on `GitHub Issues <https://github.com/OCA/sale-workflow/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed
`feedback <https://github.com/OCA/sale-workflow/issues/new?body=module:%20sale_product_catalog_extended%0Aversion:%2018.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.

Do not contact contributors directly about support or help with technical issues.

Credits
=======

Authors
-------

* Tecnativa

Contributors
------------

- `Tecnativa <https://www.tecnativa.com>`__:

- Carlos Dauden
- Carlos Roca

Maintainers
-----------

This module is maintained by the OCA.

.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org

OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.

This module is part of the `OCA/sale-workflow <https://github.com/OCA/sale-workflow/tree/18.0/sale_product_catalog_extended>`_ project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
2 changes: 2 additions & 0 deletions sale_product_catalog_extended/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from . import controllers
from . import models
20 changes: 20 additions & 0 deletions sale_product_catalog_extended/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Copyright 2025 Tecnativa - Carlos Roca
# Copyright 2025 Tecnativa - Carlos Dauden
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
{
"name": "Sale Product Catalog Extended",
"category": "Sales",
"license": "AGPL-3",
"author": "Tecnativa, Odoo Community Association (OCA)",
"version": "18.0.1.0.0",
"website": "https://github.com/OCA/sale-workflow",
"depends": ["sale"],
"data": [
"views/product_views.xml",
"views/sale_order_line_views.xml",
],
"assets": {
"web.assets_backend": ["sale_product_catalog_extended/static/src/**/*"],
},
"installable": True,
}
1 change: 1 addition & 0 deletions sale_product_catalog_extended/controllers/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import catalog
33 changes: 33 additions & 0 deletions sale_product_catalog_extended/controllers/catalog.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Copyright 2025 Tecnativa - Carlos Roca
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from odoo.http import request, route

from odoo.addons.product.controllers.catalog import ProductCatalogController


class SaleProductCatalogController(ProductCatalogController):
@route("/product/catalog/sale/open_order_line", auth="user", type="json")
def product_catalog_open_order_line(self, order_id, product_id, **kwargs):
"""Open sale order line on a given order for a given product.

:param int order_id: The order id.
:param int product_id: The product, as a `product.product` id.
:return: The id of the open sale order line.
:rtype: int
"""
order = request.env["sale.order"].browse(order_id)
return order.with_company(order.company_id)._get_catalog_order_line(
product_id,
**kwargs,
)

@route("/product/catalog/sale/get_order_line_data", auth="user", type="json")
def product_catalog_get_order_line_data(self, order_line_ids, **kwargs):
"""Open sale order line on a given order for a given product.

:param list order_line_ids: The order lines to update the record.
:return: The data of the record that is being updated.
:rtype: dict
"""
order_lines = request.env["sale.order.line"].browse(order_line_ids)
return order_lines._get_product_catalog_lines_data(**kwargs)
2 changes: 2 additions & 0 deletions sale_product_catalog_extended/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from . import product_product
from . import sale_order
81 changes: 81 additions & 0 deletions sale_product_catalog_extended/models/product_product.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# Copyright 2025 Tecnativa - Carlos Dauden
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from datetime import timedelta

from odoo import api, fields, models


class ProductProduct(models.Model):
_inherit = "product.product"

catalog_origin_data = fields.Selection(
selection=[("sale_order", "Last sales")],
store=False,
search="_search_catalog_origin_data",
)

@api.model
def search_fetch(self, domain, field_names, offset=0, limit=None, order=None):
catalog_orig_data_bool_list = [
"catalog_origin_data" in subdomain for subdomain in domain
]
if any(catalog_orig_data_bool_list):
# Get value of catalog_origin_data from domain to know which method throw.
# Then browse the ids to respect the order.
product_ids = getattr(
self,
f"_get_product_picker_data_{domain[catalog_orig_data_bool_list.index(True)][2]}",
)()
return self.browse(product_ids)
return super().search_fetch(
domain, field_names, offset=offset, limit=limit, order=order
)

@api.model
def _search_catalog_origin_data(self, operator, value):
# Hack to be able to filter by catalog_origin_data
return []

@api.model
def _product_picker_data_sale_order_domain(self):
"""Domain to find recent SO lines."""
months = 6
start = fields.Datetime.now() - timedelta(days=months * 30)
start = fields.Datetime.to_string(start)
catalog_partner_id = self.env.context.get("product_catalog_partner_id", False)
catalog_order_id = self.env.context.get("product_catalog_order_id", False)
# Search with sudo for get sale order from other commercials users
other_sales = (
self.env["sale.order"]
# .sudo()
._search(
[
("id", "!=", catalog_order_id),
("company_id", "=", self.env.company.id),
("partner_shipping_id", "=", catalog_partner_id),
("date_order", ">=", start),
]
)
)
domain = [
("order_id", "in", other_sales),
("qty_delivered", "!=", 0.0),
]
return domain

@api.model
def _get_product_picker_data_sale_order(self):
# Specific limit to allow show all products sold in recent orders
limit = int(
self.env["ir.config_parameter"]
.sudo()
.get_param("sale_order_product_picker.product_picker_last_order_limit", "0")
)
sol_groups = self.env["sale.order.line"]._read_group(
self._product_picker_data_sale_order_domain(),
groupby=["product_id"],
aggregates=["__count", "qty_delivered:sum"],
limit=limit,
order="__count desc, qty_delivered:sum desc",
)
return [g[0].id for g in sol_groups]
43 changes: 43 additions & 0 deletions sale_product_catalog_extended/models/sale_order.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Copyright 2025 Tecnativa - Carlos Roca
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from odoo import api, models


class SaleOrder(models.Model):
_inherit = "sale.order"

@api.model
def _get_catalog_order_line_filter_domain(self, product_id, **kwargs):
"""Get the domain used to filter lines from catalog."""
return [("product_id", "=", product_id)]

def _get_catalog_order_line(self, product_id, **kwargs):
"""Return the ids of the catalog order lines to be able to open
them from catalog.
"""
self.ensure_one()
return self.order_line.filtered_domain(
self._get_catalog_order_line_filter_domain(product_id, **kwargs)
).ids

def _get_action_add_from_catalog_extra_context(self):
# TODO: partner_id or shipping_partner_id?
return {
**super()._get_action_add_from_catalog_extra_context(),
"product_catalog_partner_id": self.partner_shipping_id.id,
}


class SaleOrderLine(models.Model):
_inherit = "sale.order.line"

def _get_product_catalog_lines_data(self, **kwargs):
res = super()._get_product_catalog_lines_data(**kwargs)
if len(self) > 1:
res["readOnly"] = (
self.order_id._is_readonly()
or self.product_id.sale_line_warn == "block"
or any(self.mapped(lambda sol: bool(sol.combo_item_id)))
)
res["multiLine"] = True
return res
3 changes: 3 additions & 0 deletions sale_product_catalog_extended/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[build-system]
requires = ["whool"]
build-backend = "whool.buildapi"
3 changes: 3 additions & 0 deletions sale_product_catalog_extended/readme/CONTRIBUTORS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
- [Tecnativa](https://www.tecnativa.com):
- Carlos Dauden
- Carlos Roca
2 changes: 2 additions & 0 deletions sale_product_catalog_extended/readme/DESCRIPTION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
This module extends the product catalog to allow quick editing of lines
without needing to access the sales order.
Loading