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

[ADD]product_configurator_mrp_quantity #122

Open
wants to merge 17 commits into
base: 17.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
96 changes: 96 additions & 0 deletions product_configurator_mrp_quantity/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
=================================
Product Configurator MRP Quantity
=================================

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

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

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

This module enhances the Product Configurator MRP Quantity functionality
by introducing dynamic quantity adjustments within the Product
Configurator Wizard. Users can now define specific attributes that allow
for quantity variations during the configuration process.

The quantity field becomes visible only when a specific checkbox is
selected on the corresponding attribute line within the product
template.

By default, the quantity field displays a value of "1" which can be
modified by the user during configuration.

This functionality offers greater flexibility and customization for
users by enabling:

Configurable Quantity Adjustments: Define attributes that directly
impact the quantity of materials required for a product based on user
selection. Streamlined MRP Integration: Dynamic quantity adjustments
automatically reflect in the Material Requirements Planning (MRP)
process, ensuring accurate inventory calculations.

**Table of contents**

.. contents::
:local:

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

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

* Open Source Integrators

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

- Vandan Pandeji <<[email protected]>>
- Patrick Wilson <<[email protected]>>

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-configurator <https://github.com/OCA/product-configurator/tree/17.0/product_configurator_mrp_quantity>`_ project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
11 changes: 11 additions & 0 deletions product_configurator_mrp_quantity/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from . import models
from . import wizard


def uninstall_hook(env):
"""Archived product records that have a attribute quantity value set on the product variant."""
attribute_value_qty_recs = env["product.product.attribute.value.qty"].search(
[("product_id", "!=", False)]
)
product_tmpl_ids = attribute_value_qty_recs.mapped("product_id.product_tmpl_id")
product_tmpl_ids.write({"active": False})
30 changes: 30 additions & 0 deletions product_configurator_mrp_quantity/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"name": "Product Configurator MRP Quantity",
"version": "17.0.1.0.0",
"category": "Manufacturing",
"summary": "Configuration for adding quantity in product configurator.",
"author": "Open Source Integrators,Odoo Community Association (OCA)",
"license": "AGPL-3",
"website": "https://github.com/OCA/product-configurator",
"depends": ["product_configurator", "product_configurator_mrp"],
"data": [
"security/ir.model.access.csv",
"views/product_view.xml",
"views/product_attribute_view.xml",
"wizard/product_configurator_view.xml",
"views/product_config_view.xml",
"views/attribute_value_qty_views.xml",
],
'assets': {
'web.assets_backend': [
'/product_configurator_mrp_quantity/static/src/xml/web_inner_group.xml',
'/product_configurator_mrp_quantity/static/src/scss/from_group_scss.scss'
]
},
"images": ["static/description/cover.png"],
"development_status": "Beta",
"uninstall_hook": "uninstall_hook",
"maintainer": "Open Source Integrators",
"installable": True,
"auto_install": False,
}
4 changes: 4 additions & 0 deletions product_configurator_mrp_quantity/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from . import product_config
from . import product_attribute
from . import product
from . import attribute_value_qty
176 changes: 176 additions & 0 deletions product_configurator_mrp_quantity/models/attribute_value_qty.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
import ast

from odoo import api, fields, models


class AttributeValueQty(models.Model):
_name = "attribute.value.qty"

name = fields.Char()
product_tmpl_id = fields.Many2one("product.template", string="Product Template")
product_attribute_id = fields.Many2one(
"product.attribute", string="Product Attribute"
)
product_attribute_value_id = fields.Many2one(
"product.attribute.value", string="Product Attribute Value"
)
qty = fields.Integer(string="Qty")
company_id = fields.Many2one(
"res.company", string="Company", default=lambda self: self.env.company
)
template_attri_value_id = fields.Many2one("product.template.attribute.value")

@api.depends("product_tmpl_id")
def _compute_display_name(self):
for rec in self:
rec.display_name = f"{rec.qty}"

@api.model
def _name_search(self, name, domain=None, operator="ilike", limit=None, order=None):
query = super()._name_search(name, domain, operator, limit, order)
domain = domain or []
if self.env.context.get("wizard_id"):
wiz_id = self.env[
self.env.context.get("active_model", "product.configurator")
].browse(self.env.context.get("wizard_id"))
qty_field_prefix = wiz_id._prefixes.get("qty_field")
qty_attr_id = (
self._context.get("field_name").startswith(qty_field_prefix)
and self._context.get("field_name").split(qty_field_prefix)[1]
or False
)
domain = [("product_tmpl_id", "=", wiz_id.product_tmpl_id.id)]
if (
qty_attr_id
and wiz_id.dyn_qty_field_value == self._context.get("field_name")
and wiz_id.domain_qty_ids
and wiz_id.domain_qty_ids.mapped("product_attribute_id").id
== int(qty_attr_id)
):
domain = [("id", "in", wiz_id.domain_qty_ids.ids)]
elif qty_attr_id and wiz_id.dyn_qty_field_value != self._context.get(
"field_name"
):
value_id = wiz_id.value_ids.filtered(
lambda val: val.attribute_id.id == int(qty_attr_id)
)
domains_dict = (
wiz_id.domains_dict and ast.literal_eval(wiz_id.domains_dict) or {}
)
context_value_id = self.browse(
domains_dict.get(self._context.get("field_name"))
).mapped("product_attribute_value_id")
if domains_dict and context_value_id.id != value_id.id:
value_id = context_value_id
domain_ids = self.search(
[
("product_tmpl_id", "=", wiz_id.product_tmpl_id.id),
("product_attribute_value_id", "=", value_id.id),
("product_attribute_id", "=", int(qty_attr_id)),
]
).ids
attribute_id = self._context.get("field_name").split(qty_field_prefix)
if (
not domain_ids
and domains_dict
and self._context.get("field_name") in domains_dict
):
domain_ids = domains_dict[self._context.get("field_name")]
elif (
self._context.get("field_name") not in domains_dict
and len(attribute_id) > 1
):
attribute_line_id = (
wiz_id.product_tmpl_id.attribute_line_ids.filtered(
lambda attr: attr.attribute_id.id == int(attribute_id[1])
)
)
value_id = attribute_line_id.default_val
domain_ids = self.search(
[
("product_tmpl_id", "=", wiz_id.product_tmpl_id.id),
("product_attribute_value_id", "=", value_id.id),
("product_attribute_id", "=", int(attribute_id[1])),
]
).ids
domain = [("id", "in", domain_ids)]
if name:
if wiz_id.domain_qty_ids:
domain = [
("qty", "ilike", int(name)),
("id", "in", wiz_id.domain_qty_ids.ids),
]
else:
attribute_id = self._context.get("field_name").split(
qty_field_prefix
)

attribute_line_id = (
wiz_id.product_tmpl_id.attribute_line_ids.filtered(
lambda attr: attr.attribute_id.id == int(attribute_id[1])
)
)
value_id = attribute_line_id.default_val
domain_ids = self.search(
[
("qty", "ilike", int(name)),
("product_tmpl_id", "=", wiz_id.product_tmpl_id.id),
("product_attribute_id", "=", int(attribute_id[1])),
("product_attribute_value_id", "=", value_id.id),
]
)
domain = [("id", "in", domain_ids.ids)]

return self._search(domain, limit=limit, order=order)

@api.model
def web_search_read(
self, domain, specification, offset=0, limit=None, order=None, count_limit=None
):
if self.env.context.get("wizard_id"):
wiz_id = self.env["product.configurator"].browse(
self.env.context.get("wizard_id")
)
qty_field_prefix = wiz_id._prefixes.get("qty_field")
qty_attr_id = (
self._context.get("field_name").startswith(qty_field_prefix)
and self._context.get("field_name").split(qty_field_prefix)[1]
or False
)
if (
qty_attr_id
and wiz_id.dyn_qty_field_value == self._context.get("field_name")
and wiz_id.domain_qty_ids
):
domain = [("id", "in", wiz_id.domain_qty_ids.ids)]
if qty_attr_id and wiz_id.dyn_qty_field_value != self._context.get(
"field_name"
):
value_id = wiz_id.value_ids.filtered(
lambda val: val.attribute_id.id == int(qty_attr_id)
)
domains_dict = (
wiz_id.domains_dict and ast.literal_eval(wiz_id.domains_dict) or {}
)
context_value_id = self.browse(
domains_dict.get(self._context.get("field_name"))
).mapped("product_attribute_value_id")
if domains_dict and context_value_id.id != value_id.id:
value_id = context_value_id
domain_ids = self.search(
[
("product_tmpl_id", "=", wiz_id.product_tmpl_id.id),
("product_attribute_value_id", "=", value_id.id),
("product_attribute_id", "=", int(qty_attr_id)),
]
)
domain = [("id", "in", domain_ids.ids)]

return super().web_search_read(
domain,
specification,
offset=offset,
limit=limit,
order=order,
count_limit=count_limit,
)
Loading
Loading