Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[16.0][ADD] product_catalog_stock: New module #1719

Open
wants to merge 2 commits into
base: 16.0
Choose a base branch
from
Open
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
94 changes: 94 additions & 0 deletions product_catalog_stock/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
=====================
Stock Product Catalog
=====================

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

.. |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%2Fproduct--attribute-lightgray.png?logo=github
:target: https://github.com/OCA/product-attribute/tree/16.0/product_catalog_stock
:alt: OCA/product-attribute
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/product-attribute-16-0/product-attribute-16-0-product_catalog_stock
: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/product-attribute&target_branch=16.0
:alt: Try me on Runboat

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

Implementation of the product catalog for stock pickings.

**Table of contents**

.. contents::
:local:

Usage
=====

To access the catalog from a stock picking.

1. Create a new draft picking.
2. Click on the product catalog smart button.
3. Click it and start adding products to the picking.

Known issues / Roadmap
======================

- In v17 the product catalog has the price key as mandatory. So maybe
further adaptations will be needed to support more models.

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

Bugs are tracked on `GitHub Issues <https://github.com/OCA/product-attribute/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/product-attribute/issues/new?body=module:%20product_catalog_stock%0Aversion:%2016.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
-------

* Odoo SA
* Tecnativa

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

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

- David Vidal

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/product-attribute <https://github.com/OCA/product-attribute/tree/16.0/product_catalog_stock>`_ project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
1 change: 1 addition & 0 deletions product_catalog_stock/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import models
16 changes: 16 additions & 0 deletions product_catalog_stock/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Copyright 2024 Tecnativa - David Vidal
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
{
"name": "Stock Product Catalog",
"summary": "Use the product catalog on stock pickings",
"version": "16.0.1.0.0",
"author": "Odoo SA, Tecnativa, Odoo Community Association (OCA)",
"website": "https://github.com/OCA/product-attribute",
"license": "AGPL-3",
"category": "Product",
"depends": ["stock", "product_catalog"],
"data": [
"views/stock_picking_views.xml",
"views/stock_picking_type_views.xml",
],
}
2 changes: 2 additions & 0 deletions product_catalog_stock/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from . import stock_picking
from . import stock_picking_type
152 changes: 152 additions & 0 deletions product_catalog_stock/models/stock_picking.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
# Copyright 2024 Tecnativa - David Vidal
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from collections import defaultdict

from odoo import _, api, models
from odoo.osv import expression


class StockPicking(models.Model):
_name = "stock.picking"
_inherit = ["stock.picking", "product.catalog.mixin"]

def _compute_catalog_button_text(self):
self.catalog_button_text = _("Back to picking")

Check warning on line 14 in product_catalog_stock/models/stock_picking.py

View check run for this annotation

Codecov / codecov/patch

product_catalog_stock/models/stock_picking.py#L14

Added line #L14 was not covered by tests

def _get_action_add_from_catalog_extra_context(self):
return {

Check warning on line 17 in product_catalog_stock/models/stock_picking.py

View check run for this annotation

Codecov / codecov/patch

product_catalog_stock/models/stock_picking.py#L17

Added line #L17 was not covered by tests
**super()._get_action_add_from_catalog_extra_context(),
"order_id": self.id,
}

def _default_order_line_values(self):
default_data = super()._default_order_line_values()
new_default_data = self.env["stock.move"]._get_product_catalog_lines_data()
return {**default_data, **new_default_data}

Check warning on line 25 in product_catalog_stock/models/stock_picking.py

View check run for this annotation

Codecov / codecov/patch

product_catalog_stock/models/stock_picking.py#L23-L25

Added lines #L23 - L25 were not covered by tests

def _get_product_catalog_domain(self):
return expression.AND(

Check warning on line 28 in product_catalog_stock/models/stock_picking.py

View check run for this annotation

Codecov / codecov/patch

product_catalog_stock/models/stock_picking.py#L28

Added line #L28 was not covered by tests
[
super()._get_product_catalog_domain(),
[("type", "in", ["consu", "product"])],
]
)

def _get_product_catalog_record_lines(self, product_ids):
grouped_moves = defaultdict(lambda: self.env["stock.move"])
for move in self.move_ids:
if move.product_id.id not in product_ids:
continue
grouped_moves[move.product_id] |= move
return grouped_moves

Check warning on line 41 in product_catalog_stock/models/stock_picking.py

View check run for this annotation

Codecov / codecov/patch

product_catalog_stock/models/stock_picking.py#L39-L41

Added lines #L39 - L41 were not covered by tests

@api.model
def _prepare_stock_move_vals_from_catalog(self, product_id, quantity):
self.ensure_one()
product_id = self.env["product.product"].browse(product_id)
return {

Check warning on line 47 in product_catalog_stock/models/stock_picking.py

View check run for this annotation

Codecov / codecov/patch

product_catalog_stock/models/stock_picking.py#L45-L47

Added lines #L45 - L47 were not covered by tests
"name": product_id.display_name,
"product_id": product_id.id,
"product_uom_qty": quantity,
"product_uom": product_id.uom_id.id,
"location_id": self.location_id.id,
"location_dest_id": self.location_dest_id.id,
"picking_id": self.id,
"state": self.state,
"picking_type_id": self.picking_type_id.id,
"restrict_partner_id": self.owner_id.id,
"company_id": self.company_id.id,
"partner_id": self.partner_id.id,
# Put it at the end of the order
"sequence": ((self.move_ids and self.move_ids[-1].sequence + 1) or 10),
}

def _update_order_line_info(self, product_id, quantity, **kwargs):
"""Update stock move information for a given product or create a
new one if none exists yet.
:param int product_id: The product, as a `product.product` id.
:return: There's no price unit so we return always None show nothing is shown
:rtype: None
"""
move = self.move_ids.filtered(lambda move: move.product_id.id == product_id)
if move:
if quantity != 0:
move.product_uom_qty = quantity

Check warning on line 74 in product_catalog_stock/models/stock_picking.py

View check run for this annotation

Codecov / codecov/patch

product_catalog_stock/models/stock_picking.py#L74

Added line #L74 was not covered by tests
elif self.state == "draft":
move.unlink()
return None

Check warning on line 77 in product_catalog_stock/models/stock_picking.py

View check run for this annotation

Codecov / codecov/patch

product_catalog_stock/models/stock_picking.py#L76-L77

Added lines #L76 - L77 were not covered by tests
else:
move.product_uom_qty = 0

Check warning on line 79 in product_catalog_stock/models/stock_picking.py

View check run for this annotation

Codecov / codecov/patch

product_catalog_stock/models/stock_picking.py#L79

Added line #L79 was not covered by tests
elif quantity > 0:
move = self.env["stock.move"].create(

Check warning on line 81 in product_catalog_stock/models/stock_picking.py

View check run for this annotation

Codecov / codecov/patch

product_catalog_stock/models/stock_picking.py#L81

Added line #L81 was not covered by tests
self._prepare_stock_move_vals_from_catalog(product_id, quantity)
)
return None

Check warning on line 84 in product_catalog_stock/models/stock_picking.py

View check run for this annotation

Codecov / codecov/patch

product_catalog_stock/models/stock_picking.py#L84

Added line #L84 was not covered by tests

def _is_readonly(self):
"""Return Whether the sale order is read-only or not based on the state or the
lock status.

A sale order is considered read-only if its state is 'cancel' or if the sale
order is locked.

:return: Whether the sale order is read-only or not.
:rtype: bool
"""
self.ensure_one()
return self.state in ["cancel", "done"]

Check warning on line 97 in product_catalog_stock/models/stock_picking.py

View check run for this annotation

Codecov / codecov/patch

product_catalog_stock/models/stock_picking.py#L96-L97

Added lines #L96 - L97 were not covered by tests


class StockMove(models.Model):
_inherit = "stock.move"

def _get_product_catalog_lines_data(self, **kwargs):
"""Return information about sale order lines in `self`.

If `self` is empty, this method returns only the default value(s) needed for
the product catalog. In this case, the quantity that equals 0.

Otherwise, it returns a quantity and a price based on the product of the SOL(s)
and whether the product is read-only or not.

A product is considered read-only if the picking is cancelled or done.

Note: This method cannot be called with multiple records that have different
products linked.

:raise odoo.exceptions.ValueError: ``len(self.product_id) != 1``
:rtype: dict
:return: A dict with the following structure:
{
'quantity': float,
'readOnly': bool,
}
"""
if len(self) == 1:
res = {

Check warning on line 126 in product_catalog_stock/models/stock_picking.py

View check run for this annotation

Codecov / codecov/patch

product_catalog_stock/models/stock_picking.py#L126

Added line #L126 was not covered by tests
"quantity": self.product_uom_qty,
"readOnly": self.picking_id.state in ["cancel", "done"],
}
return res

Check warning on line 130 in product_catalog_stock/models/stock_picking.py

View check run for this annotation

Codecov / codecov/patch

product_catalog_stock/models/stock_picking.py#L130

Added line #L130 was not covered by tests
elif self:
self.product_id.ensure_one()

Check warning on line 132 in product_catalog_stock/models/stock_picking.py

View check run for this annotation

Codecov / codecov/patch

product_catalog_stock/models/stock_picking.py#L132

Added line #L132 was not covered by tests
res = {
"readOnly": True,
"quantity": sum(
self.mapped(
lambda move: move.product_uom._compute_quantity(
qty=move.product_uom_qty,
to_unit=move.product_id.uom_id,
)
)
),
}
return res

Check warning on line 144 in product_catalog_stock/models/stock_picking.py

View check run for this annotation

Codecov / codecov/patch

product_catalog_stock/models/stock_picking.py#L144

Added line #L144 was not covered by tests
else:
return {

Check warning on line 146 in product_catalog_stock/models/stock_picking.py

View check run for this annotation

Codecov / codecov/patch

product_catalog_stock/models/stock_picking.py#L146

Added line #L146 was not covered by tests
"quantity": 0,
}

def action_add_from_catalog(self):
picking = self.env["stock.picking"].browse(self.env.context.get("order_id"))
return picking.action_add_from_catalog()

Check warning on line 152 in product_catalog_stock/models/stock_picking.py

View check run for this annotation

Codecov / codecov/patch

product_catalog_stock/models/stock_picking.py#L151-L152

Added lines #L151 - L152 were not covered by tests
24 changes: 24 additions & 0 deletions product_catalog_stock/models/stock_picking_type.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Copyright 2024 Tecnativa - David Vidal
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from odoo import models
from odoo.tests import Form


class StockPickingType(models.Model):
_inherit = "stock.picking.type"

def action_new_draft_picking_from_catalog(self):
"""Create a new draft picking from the catalog view"""
picking_form = Form(

Check warning on line 12 in product_catalog_stock/models/stock_picking_type.py

View check run for this annotation

Codecov / codecov/patch

product_catalog_stock/models/stock_picking_type.py#L12

Added line #L12 was not covered by tests
self.env["stock.picking"].with_context(
search_default_picking_type_id=self.ids,
default_picking_type_id=self.id,
contact_display="partner_address",
)
)
picking = picking_form.save()
action = picking.action_add_from_catalog()

Check warning on line 20 in product_catalog_stock/models/stock_picking_type.py

View check run for this annotation

Codecov / codecov/patch

product_catalog_stock/models/stock_picking_type.py#L19-L20

Added lines #L19 - L20 were not covered by tests
# So we can go back safely to the new picking instead of returning to the
# previous screen
action["target"] = "main"
return action

Check warning on line 24 in product_catalog_stock/models/stock_picking_type.py

View check run for this annotation

Codecov / codecov/patch

product_catalog_stock/models/stock_picking_type.py#L23-L24

Added lines #L23 - L24 were not covered by tests
2 changes: 2 additions & 0 deletions product_catalog_stock/readme/CONTRIBUTORS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
- [Tecnativa](https://tecnativa.com)
- David Vidal
1 change: 1 addition & 0 deletions product_catalog_stock/readme/DESCRIPTION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Implementation of the product catalog for stock pickings.
2 changes: 2 additions & 0 deletions product_catalog_stock/readme/ROADMAP.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
- In v17 the product catalog has the price key as mandatory. So maybe further
adaptations will be needed to support more models.
5 changes: 5 additions & 0 deletions product_catalog_stock/readme/USAGE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
To access the catalog from a stock picking.

1. Create a new draft picking.
2. Click on the product catalog smart button.
3. Click it and start adding products to the picking.
Loading
Loading