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

[17.0] [MIG] sale_packaging_default: Migration to 17.0 #3334

Open
wants to merge 25 commits into
base: 17.0
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
293f18e
[ADD] sale_packaging_default: default packaging for sales
yajo Aug 28, 2023
16b26ad
[UPD] Update sale_packaging_default.pot
Aug 31, 2023
086766d
[UPD] README.rst
OCA-git-bot Aug 31, 2023
c9b1cfc
[UPD] README.rst
OCA-git-bot Sep 3, 2023
c1179b7
Added translation using Weblate (Spanish)
Gelojr Nov 20, 2023
23f8ad9
Translated using Weblate (Spanish)
Gelojr Nov 20, 2023
ed8b36b
[FIX] sale_packaging_default: reorder SO sub-form view too
yajo Nov 21, 2023
646a338
[FIX] sale_packaging_default: setting product_uom_qty to 0 empties pa…
yajo Nov 21, 2023
d587b79
[BOT] post-merge updates
OCA-git-bot Nov 21, 2023
971a449
[BOT] post-merge updates
OCA-git-bot Nov 21, 2023
f6fb670
[FIX] sale_packaging_default: compatible with `sale_order_product_pic…
yajo Nov 27, 2023
c4ac0cb
[BOT] post-merge updates
OCA-git-bot Nov 28, 2023
c780f42
Added translation using Weblate (Italian)
mymage Dec 1, 2023
631db13
Translated using Weblate (Italian)
mymage Dec 4, 2023
c02fbe9
[REF] sale_packaging_default: remove sale_default field
yajo Dec 1, 2023
382222f
[UPD] Update sale_packaging_default.pot
Dec 12, 2023
2c170ad
[BOT] post-merge updates
OCA-git-bot Dec 12, 2023
b2209b7
Update translation files
weblate Dec 12, 2023
7dba725
sale_packaging_default: make packaging lookup reusable
simahawk Feb 19, 2024
06b6792
[BOT] post-merge updates
OCA-git-bot Feb 19, 2024
dabb14b
Translated using Weblate (Spanish)
yajo Mar 7, 2024
0e99a86
[IMP] sale_packaging_default: keep packaging qty when changing product
yajo Mar 15, 2024
7fba1fe
[BOT] post-merge updates
OCA-git-bot Mar 18, 2024
4968699
[IMP] sale_packaging_default: pre-commit auto fixes
bizzappdev Sep 28, 2024
4a0292a
[MIG] sale_packaging_default: Migration to 17.0
bizzappdev Sep 28, 2024
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
147 changes: 147 additions & 0 deletions sale_packaging_default/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
===========================
Default packaging for sales
===========================

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

.. |badge1| image:: https://img.shields.io/badge/maturity-Alpha-red.png
:target: https://odoo-community.org/page/development-status
:alt: Alpha
.. |badge2| image:: https://img.shields.io/badge/licence-LGPL--3-blue.png
:target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html
:alt: License: LGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fsale--workflow-lightgray.png?logo=github
:target: https://github.com/OCA/sale-workflow/tree/17.0/sale_packaging_default
: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-17-0/sale-workflow-17-0-sale_packaging_default
: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=17.0
:alt: Try me on Runboat

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

This module simplifies and emphasizes the usage of packaging in sales
orders.

- Packaging fields in sale order lines appear before product quantity
fields.
- When selecting a product to sell, its default packaging is added
automatically.

.. IMPORTANT::
This is an alpha version, the data model and design can change at any time without warning.
Only for development or testing purpose, do not use in production.
`More details on development status <https://odoo-community.org/page/development-status>`_

**Table of contents**

.. contents::
:local:

Use Cases / Context
===================

Some companies, like food distributors, need to emphasize the usage of
product packaging in the sale process.

Product packaging in Odoo is designed to be computed automatically when
you choose the final amount of products to sell. For example, if you
sell 12 kgs of apples and those can be packaged by bags of 4kg, you'll
get automatically suggested to sell 3 bags.

Although you can still do that, with this module the natural usage is
inverted: it's easier for you to select the packaging and quantity
first, and then the final amount of products is computed automatically.
Following the same example, you'll choose bags, then 3, and then the
12kg will be computed automatically.

Configuration
=============

To configure this module, you need to:

1. Go to *Sales > Configuration > Settings*.
2. Under *Product Catalog*, enable *Product Packagings*.

Usage
=====

To use this module, you need to configure a product with packaging:

1. Go to *Sales > Products > Products* and select or create a product.
2. In the *Inventory* tab, add some packaging(s).
3. Enable *Sales* and in one packaging.
4. Sort the packaging options at will. The first one enabled for *Sales*
will be considered the default one.

Then you have to sell it:

1. Go to *Sales > Orders > Quotations* and create a new quotation.
2. Select any customer.
3. Select that product.

You will notice that:

- The product is added with the default sale packaging.
- The packaging quantity is set to 1 packaging unit.
- The product UoM quantity is set to the amount of units contained in 1
packaging.
- When changing to another product, instead of keeping the amount of
UoM units, we now keep the packaging qty, and the UoM qty is
recomputed accordingly.

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_packaging_default%0Aversion:%2017.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
-------

* Moduon

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

- Jairo Llopis (`Moduon <https://www.moduon.team/>`__)

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.

.. |maintainer-yajo| image:: https://github.com/yajo.png?size=40px
:target: https://github.com/yajo
:alt: yajo

Current `maintainer <https://odoo-community.org/page/maintainer-role>`__:

|maintainer-yajo|

This module is part of the `OCA/sale-workflow <https://github.com/OCA/sale-workflow/tree/17.0/sale_packaging_default>`_ 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 sale_packaging_default/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import models
20 changes: 20 additions & 0 deletions sale_packaging_default/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Copyright 2023 Moduon Team S.L.
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl-3.0)

{
"name": "Default packaging for sales",
"version": "17.0.1.0.0",
"summary": "Simplify using products default packaging for sales",
"development_status": "Alpha",
"category": "Sales",
"website": "https://github.com/OCA/sale-workflow",
"author": "Moduon, Odoo Community Association (OCA)",
"maintainers": ["yajo"],
"license": "LGPL-3",
"application": False,
"installable": True,
"depends": ["sale"],
"data": [
"views/sale_order_view.xml",
],
}
37 changes: 37 additions & 0 deletions sale_packaging_default/i18n/es.po
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * sale_packaging_default
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 16.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2024-03-07 12:35+0000\n"
"Last-Translator: Jairo Llopis <[email protected]>\n"
"Language-Team: none\n"
"Language: es\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 4.17\n"

#. module: sale_packaging_default
#: model:ir.model,name:sale_packaging_default.model_product_packaging
msgid "Product Packaging"
msgstr "Envase del producto"

#. module: sale_packaging_default
#: model:ir.model,name:sale_packaging_default.model_sale_order_line
msgid "Sales Order Line"
msgstr "Línea de Pedido de Venta"

#~ msgid "Default for sales"
#~ msgstr "Por defecto para ventas"

#~ msgid ""
#~ "The first packaging with this option checked will be used by default in "
#~ "sales orders."
#~ msgstr ""
#~ "El primer empaquetado de la lista con esta opción marcada es el que se "
#~ "utilizará por defecto en los pedidos de venta."
37 changes: 37 additions & 0 deletions sale_packaging_default/i18n/it.po
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * sale_packaging_default
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 16.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2023-12-04 09:34+0000\n"
"Last-Translator: mymage <[email protected]>\n"
"Language-Team: none\n"
"Language: it\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 4.17\n"

#. module: sale_packaging_default
#: model:ir.model,name:sale_packaging_default.model_product_packaging
msgid "Product Packaging"
msgstr "Imballaggio prodotto"

#. module: sale_packaging_default
#: model:ir.model,name:sale_packaging_default.model_sale_order_line
msgid "Sales Order Line"
msgstr "Riga ordine di vendita"

#~ msgid "Default for sales"
#~ msgstr "Predefinito per le vendite"

#~ msgid ""
#~ "The first packaging with this option checked will be used by default in "
#~ "sales orders."
#~ msgstr ""
#~ "Il primo imballaggio con questa opzione selezionata verrà utilizzato in "
#~ "modo predefinito negli ordini di vendita."
24 changes: 24 additions & 0 deletions sale_packaging_default/i18n/sale_packaging_default.pot
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * sale_packaging_default
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 16.0\n"
"Report-Msgid-Bugs-To: \n"
"Last-Translator: \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"

#. module: sale_packaging_default
#: model:ir.model,name:sale_packaging_default.model_product_packaging
msgid "Product Packaging"
msgstr ""

#. module: sale_packaging_default
#: model:ir.model,name:sale_packaging_default.model_sale_order_line
msgid "Sales Order Line"
msgstr ""
2 changes: 2 additions & 0 deletions sale_packaging_default/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from . import product_packaging
from . import sale_order_line
13 changes: 13 additions & 0 deletions sale_packaging_default/models/product_packaging.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Copyright 2023 Moduon Team S.L.
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl-3.0)
from odoo import models


class ProductPackaging(models.Model):
_inherit = "product.packaging"

def _find_suitable_product_packaging(self, product_qty, uom_id):
"""Find nothing if you want to keep what was there."""
if self.env.context.get("keep_product_packaging"):
return self.browse()
return super()._find_suitable_product_packaging(product_qty, uom_id)
86 changes: 86 additions & 0 deletions sale_packaging_default/models/sale_order_line.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# Copyright 2023 Moduon Team S.L.
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl-3.0)
from contextlib import suppress

from odoo import api, fields, models


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

def onchange(self, values, field_name, field_onchange):
"""Record which field was being changed."""
if isinstance(field_name, list):
names = set(field_name)
elif field_name:
names = {field_name}

Check warning on line 16 in sale_packaging_default/models/sale_order_line.py

View check run for this annotation

Codecov / codecov/patch

sale_packaging_default/models/sale_order_line.py#L16

Added line #L16 was not covered by tests
else:
names = set()

Check warning on line 18 in sale_packaging_default/models/sale_order_line.py

View check run for this annotation

Codecov / codecov/patch

sale_packaging_default/models/sale_order_line.py#L18

Added line #L18 was not covered by tests
_self = self.with_context(changing_fields=names)
return super(SaleOrderLine, _self).onchange(values, field_name, field_onchange)

@api.depends("product_id", "product_uom_qty", "product_uom")
def _compute_product_packaging_id(self):
"""Set a default packaging for sales if possible."""
for line in self:
if line.product_id != line.product_packaging_id.product_id:
line.product_packaging_id = line._get_default_packaging(line.product_id)
result = super()._compute_product_packaging_id()
# If there's no way to package the desired qty, remove the packaging.
# It is only done when the user is currently manually setting
# `product_uom_qty` to zero. In other cases, we are maybe getting
# default values and this difference will get fixed by other compute
# methods later.
if (
self.env.context.get("changing_fields")
and "product_uom_qty" not in self.env.context["changing_fields"]
):
return result
for line in self:
with suppress(ZeroDivisionError):
if (
line.product_uom_qty
and line.product_uom_qty % line.product_packaging_id.qty
):
line.product_packaging_id = False
return result

@api.model
def _get_default_packaging(self, product):
return fields.first(
product.packaging_ids.filtered_domain([("sales", "=", True)])
)

@api.depends("product_packaging_id", "product_uom", "product_uom_qty")
def _compute_product_packaging_qty(self):
"""Set a valid packaging quantity."""
changing_fields = self.env.context.get("changing_fields", set())
# Keep the packaging qty when changing the product
if "product_id" in changing_fields and all(
line.product_id and line.product_packaging_qty for line in self
):
return
result = super()._compute_product_packaging_qty()
for line in self:
if not line.product_packaging_id:
continue
# Reset to 1 packaging if it's empty or not a whole number
if not line.product_packaging_qty or line.product_packaging_qty % 1:
line.product_packaging_qty = int(
"product_uom_qty" not in changing_fields
)
return result

@api.depends(
"display_type",
"product_id",
"product_packaging_id",
"product_packaging_qty",
)
def _compute_product_uom_qty(self):
# Avoid a circular dependency. Upstream `product_uom_qty` has an
# undeclared dependency over `product_packaging_qty`, which depends
# again on `product_uom_qty`.
_self = self.with_context(keep_product_packaging=True)
result = super(SaleOrderLine, _self)._compute_product_uom_qty()
return result
3 changes: 3 additions & 0 deletions sale_packaging_default/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[build-system]
requires = ["whool"]
build-backend = "whool.buildapi"
4 changes: 4 additions & 0 deletions sale_packaging_default/readme/CONFIGURE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
To configure this module, you need to:

1. Go to *Sales \> Configuration \> Settings*.
2. Under *Product Catalog*, enable *Product Packagings*.
12 changes: 12 additions & 0 deletions sale_packaging_default/readme/CONTEXT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
Some companies, like food distributors, need to emphasize the usage of product
packaging in the sale process.

Product packaging in Odoo is designed to be computed automatically when you
choose the final amount of products to sell. For example, if you sell 12 kgs of
apples and those can be packaged by bags of 4kg, you'll get automatically
suggested to sell 3 bags.

Although you can still do that, with this module the natural usage is inverted:
it's easier for you to select the packaging and quantity first, and then the
final amount of products is computed automatically. Following the same example,
you'll choose bags, then 3, and then the 12kg will be computed automatically.
1 change: 1 addition & 0 deletions sale_packaging_default/readme/CONTRIBUTORS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Jairo Llopis ([Moduon](https://www.moduon.team/))
Loading
Loading