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

[14.0][ADD] sale_stock_mto_as_mts_orderpoint_mrp #1701

Open
wants to merge 2 commits into
base: 14.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
3 changes: 2 additions & 1 deletion sale_stock_mto_as_mts_orderpoint/models/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from . import product
from . import product_template
from . import product_product
from . import sale_order
from . import stock_move
from . import stock_warehouse
13 changes: 13 additions & 0 deletions sale_stock_mto_as_mts_orderpoint/models/product_product.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Copyright 2020 Camptocamp SA
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
from odoo import models


class ProductProduct(models.Model):

_inherit = "product.product"

def _is_mto(self):
self.ensure_one()
mto_route = self.env.ref("stock.route_warehouse0_mto")
return mto_route in self.route_ids
51 changes: 23 additions & 28 deletions sale_stock_mto_as_mts_orderpoint/models/sale_order.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Copyright 2020 Camptocamp SA
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
from odoo import models
from odoo import api, models
from odoo.tools import groupby


class SaleOrderLine(models.Model):
Expand All @@ -14,37 +15,31 @@ def _action_launch_stock_rule(self, previous_product_uom_qty=False):
self._run_orderpoints_for_mto_products()
return res

@api.model
def _get_procurement_wiz_for_orderpoint_ids(self, context):
model = self.env["make.procurement.orderpoint"]
return model.with_context(**context).create({})

def _run_orderpoints_for_mto_products(self):
orderpoints_to_procure_ids = []
mto_route = self.env.ref("stock.route_warehouse0_mto", raise_if_not_found=False)
if not mto_route:
return
for line in self:
delivery_moves = line.move_ids.filtered(
orderpoints_to_procure = self.env["stock.warehouse.orderpoint"]
lines_per_warehouse = groupby(
self, key=lambda l: l.warehouse_id or l.order_id.warehouse_id
)
for warehouse, line_list in lines_per_warehouse:
lines = self.browse([line.id for line in line_list])
delivery_moves = lines.move_ids.filtered(
lambda m: m.picking_id.picking_type_code == "outgoing"
and m.state not in ("done", "cancel")
)
for delivery_move in delivery_moves:
if (
not delivery_move.is_from_mto_route
and mto_route not in delivery_move.product_id.route_ids
):
continue
if not delivery_move.warehouse_id.mto_as_mts:
continue
orderpoint = line._get_mto_orderpoint(delivery_move.product_id)
if orderpoint.procure_recommended_qty:
orderpoints_to_procure_ids.append(orderpoint.id)
wiz = (
self.env["make.procurement.orderpoint"]
.with_context(
**{
"active_model": "stock.warehouse.orderpoint",
"active_ids": orderpoints_to_procure_ids,
}
)
.create({})
)
if warehouse.mto_as_mts:
orderpoints_to_procure |= delivery_moves._get_mto_as_mts_orderpoints(
warehouse
)
context = {
"active_model": "stock.warehouse.orderpoint",
"active_ids": orderpoints_to_procure.ids,
}
wiz = self._get_procurement_wiz_for_orderpoint_ids(context)
wiz.make_procurement()

def _get_mto_orderpoint(self, product_id):
Expand Down
51 changes: 50 additions & 1 deletion sale_stock_mto_as_mts_orderpoint/models/stock_move.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Copyright 2020 Camptocamp SA
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
from odoo import fields, models
from odoo import api, fields, models


class StockMove(models.Model):
Expand All @@ -16,3 +16,52 @@
else:
for move in self:
move.is_from_mto_route = move.rule_id.route_id == mto_route

@api.model
def _get_mto_orderpoint(self, warehouse, product):
Comment on lines +20 to +21
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved it to product.product and try to be close to v16 implementation https://github.com/OCA/stock-logistics-orderpoint/blob/16.0/stock_orderpoint_mto_as_mts/models/product_product.py#L26
You could backport the content of product_product.py from v16.

The main difference in v16 is that the trigger is automatic and you don't need to call the wizard

orderpoint_model = self.env["stock.warehouse.orderpoint"]
orderpoint = orderpoint_model.with_context(active_test=False).search(
[
("product_id", "=", product.id),
(
"location_id",
"=",
warehouse._get_locations_for_mto_orderpoints().id,
),
],
limit=1,
)
if orderpoint and not orderpoint.active:
orderpoint.write(

Check warning on line 35 in sale_stock_mto_as_mts_orderpoint/models/stock_move.py

View check run for this annotation

Codecov / codecov/patch

sale_stock_mto_as_mts_orderpoint/models/stock_move.py#L35

Added line #L35 was not covered by tests
{"active": True, "product_min_qty": 0.0, "product_max_qty": 0.0}
)
elif not orderpoint:
orderpoint = (
self.env["stock.warehouse.orderpoint"]
.sudo()
.create(
{
"product_id": product.id,
"warehouse_id": warehouse.id,
"location_id": (
warehouse._get_locations_for_mto_orderpoints().id
),
"product_min_qty": 0.0,
"product_max_qty": 0.0,
}
)
)
return orderpoint

def _get_mto_as_mts_orderpoints(self, warehouse):
orderpoint_to_procure = self.env["stock.warehouse.orderpoint"]
mto_route = self.env.ref("stock.route_warehouse0_mto", raise_if_not_found=False)
if not mto_route:
return

Check warning on line 60 in sale_stock_mto_as_mts_orderpoint/models/stock_move.py

View check run for this annotation

Codecov / codecov/patch

sale_stock_mto_as_mts_orderpoint/models/stock_move.py#L60

Added line #L60 was not covered by tests
for move in self:
if not (move.product_id._is_mto() or move.is_from_mto_route):
continue
orderpoint = move._get_mto_orderpoint(warehouse, move.product_id)
if orderpoint.procure_recommended_qty:
orderpoint_to_procure |= orderpoint
return orderpoint_to_procure
86 changes: 86 additions & 0 deletions sale_stock_mto_as_mts_orderpoint_mrp/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
======================================
Sale Stock Mto As Mts Orderpoint - BOM
======================================

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

.. |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-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%2Fstock--logistics--workflow-lightgray.png?logo=github
:target: https://github.com/OCA/stock-logistics-workflow/tree/14.0/sale_stock_mto_as_mts_orderpoint_mrp
:alt: OCA/stock-logistics-workflow
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/stock-logistics-workflow-14-0/stock-logistics-workflow-14-0-sale_stock_mto_as_mts_orderpoint_mrp
: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/stock-logistics-workflow&target_branch=14.0
:alt: Try me on Runboat

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

Glue module between Sale Stock MTO as MTS Orderpoint and MRP.

This allows to create orderpoints for Bills of Materials, and to set them as MTO.

.. 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:

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

Bugs are tracked on `GitHub Issues <https://github.com/OCA/stock-logistics-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/stock-logistics-workflow/issues/new?body=module:%20sale_stock_mto_as_mts_orderpoint_mrp%0Aversion:%2014.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
~~~~~~~

* Camptocamp

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-mmequignon| image:: https://github.com/mmequignon.png?size=40px
:target: https://github.com/mmequignon
:alt: mmequignon

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

|maintainer-mmequignon|

This module is part of the `OCA/stock-logistics-workflow <https://github.com/OCA/stock-logistics-workflow/tree/14.0/sale_stock_mto_as_mts_orderpoint_mrp>`_ 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_stock_mto_as_mts_orderpoint_mrp/__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_stock_mto_as_mts_orderpoint_mrp/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Copyright 2024 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)

{
"name": "Sale Stock Mto As Mts Orderpoint - BOM",
"summary": "Integration module between sale_stock_mto_as_mts_orderpoint and mrp",
"version": "14.0.1.0.0",
"development_status": "Alpha",
"category": "Operations/Inventory/Delivery",
"website": "https://github.com/OCA/stock-logistics-workflow",
"author": "Camptocamp, Odoo Community Association (OCA)",
"maintainers": ["mmequignon"],
"license": "AGPL-3",
"installable": True,
"depends": [
"sale_stock_mto_as_mts_orderpoint",
"mrp",
"mrp_bom_find_ignore",
],
}
3 changes: 3 additions & 0 deletions sale_stock_mto_as_mts_orderpoint_mrp/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from . import sale_order_line
from . import stock_move
from . import stock_warehouse_orderpoint
14 changes: 14 additions & 0 deletions sale_stock_mto_as_mts_orderpoint_mrp/models/sale_order_line.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Copyright 2024 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)


from odoo import api, models


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

@api.model
def _get_procurement_wiz_for_orderpoint_ids(self, context):
context.update({"ignore_bom_find": True})
return super()._get_procurement_wiz_for_orderpoint_ids(context)
48 changes: 48 additions & 0 deletions sale_stock_mto_as_mts_orderpoint_mrp/models/stock_move.py
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should point out, that this can only work for simple bom kits. (Where no component is a kit it self)
A more complex bom structure like.
Product 1

  • Component 1.1

  • Component 1.2 (kit)
    -- Component 1.2.1
    -- Component 1.2.2

This can never order all of the necessary products.
Since there will be 1 move (1.1) linked to bom 1
and 2 moves (1.2.1, 1.2.2) linked to bom 1.2.

The move from bom 1 can not be reordered by mto because of this if bom_lines != move_bom_lines:
it would be just possible to reorder Component 1.2 .

Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Copyright 2024 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)

from odoo import models
from odoo.tools import groupby


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

def all_moves_can_be_bought(self):
for move in self:
if not move.product_id.purchase_ok:
return False
return True

Check warning on line 15 in sale_stock_mto_as_mts_orderpoint_mrp/models/stock_move.py

View check run for this annotation

Codecov / codecov/patch

sale_stock_mto_as_mts_orderpoint_mrp/models/stock_move.py#L14-L15

Added lines #L14 - L15 were not covered by tests
jbaudoux marked this conversation as resolved.
Show resolved Hide resolved

def _get_mto_as_mts_orderpoints(self, warehouse):
orderpoints_to_procure = self.env["stock.warehouse.orderpoint"]

Check warning on line 18 in sale_stock_mto_as_mts_orderpoint_mrp/models/stock_move.py

View check run for this annotation

Codecov / codecov/patch

sale_stock_mto_as_mts_orderpoint_mrp/models/stock_move.py#L18

Added line #L18 was not covered by tests
mmequignon marked this conversation as resolved.
Show resolved Hide resolved

if self.all_moves_can_be_bought():
return super()._get_mto_as_mts_orderpoints(warehouse)

Check warning on line 21 in sale_stock_mto_as_mts_orderpoint_mrp/models/stock_move.py

View check run for this annotation

Codecov / codecov/patch

sale_stock_mto_as_mts_orderpoint_mrp/models/stock_move.py#L21

Added line #L21 was not covered by tests

seen_moves = self.browse()

Check warning on line 23 in sale_stock_mto_as_mts_orderpoint_mrp/models/stock_move.py

View check run for this annotation

Codecov / codecov/patch

sale_stock_mto_as_mts_orderpoint_mrp/models/stock_move.py#L23

Added line #L23 was not covered by tests
for bom, bom_move_list in groupby(self, key=lambda m: m.bom_line_id.bom_id):
bom_moves = self.browse([move.id for move in bom_move_list])
if not bom or not bom_moves:
# In case a move doesn't have a bom, do nothing
continue

Check warning on line 28 in sale_stock_mto_as_mts_orderpoint_mrp/models/stock_move.py

View check run for this annotation

Codecov / codecov/patch

sale_stock_mto_as_mts_orderpoint_mrp/models/stock_move.py#L28

Added line #L28 was not covered by tests

bom_product = bom.product_id
bom_lines = bom.bom_line_ids
move_bom_lines = bom_moves.bom_line_id

Check warning on line 32 in sale_stock_mto_as_mts_orderpoint_mrp/models/stock_move.py

View check run for this annotation

Codecov / codecov/patch

sale_stock_mto_as_mts_orderpoint_mrp/models/stock_move.py#L30-L32

Added lines #L30 - L32 were not covered by tests
if bom_lines != move_bom_lines:
continue

Check warning on line 34 in sale_stock_mto_as_mts_orderpoint_mrp/models/stock_move.py

View check run for this annotation

Codecov / codecov/patch

sale_stock_mto_as_mts_orderpoint_mrp/models/stock_move.py#L34

Added line #L34 was not covered by tests

is_mto = bom_product._is_mto() or all(bom_moves.is_from_mto_route)

Check warning on line 36 in sale_stock_mto_as_mts_orderpoint_mrp/models/stock_move.py

View check run for this annotation

Codecov / codecov/patch

sale_stock_mto_as_mts_orderpoint_mrp/models/stock_move.py#L36

Added line #L36 was not covered by tests
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
is_mto = bom_product._is_mto() or all(bom_moves.is_from_mto_route)
is_mto = bom_product._is_mto() or all(bom_move.is_from_mto_route for bom_move in bom_moves)

if not bom_moves.all_moves_can_be_bought() and is_mto:
orderpoint = self._get_mto_orderpoint(warehouse, bom_product)

Check warning on line 38 in sale_stock_mto_as_mts_orderpoint_mrp/models/stock_move.py

View check run for this annotation

Codecov / codecov/patch

sale_stock_mto_as_mts_orderpoint_mrp/models/stock_move.py#L38

Added line #L38 was not covered by tests
if orderpoint.procure_recommended_qty:
orderpoints_to_procure |= orderpoint

Check warning on line 40 in sale_stock_mto_as_mts_orderpoint_mrp/models/stock_move.py

View check run for this annotation

Codecov / codecov/patch

sale_stock_mto_as_mts_orderpoint_mrp/models/stock_move.py#L40

Added line #L40 was not covered by tests
# All bom_moves has been handled
seen_moves |= bom_moves

Check warning on line 42 in sale_stock_mto_as_mts_orderpoint_mrp/models/stock_move.py

View check run for this annotation

Codecov / codecov/patch

sale_stock_mto_as_mts_orderpoint_mrp/models/stock_move.py#L42

Added line #L42 was not covered by tests

remaining_moves = self - seen_moves
return (

Check warning on line 45 in sale_stock_mto_as_mts_orderpoint_mrp/models/stock_move.py

View check run for this annotation

Codecov / codecov/patch

sale_stock_mto_as_mts_orderpoint_mrp/models/stock_move.py#L44-L45

Added lines #L44 - L45 were not covered by tests
super(StockMove, remaining_moves)._get_mto_as_mts_orderpoints(warehouse)
| orderpoints_to_procure
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Copyright 2024 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)

from odoo import api, models


class StockWarehouseOrderpoint(models.Model):
_inherit = "stock.warehouse.orderpoint"

@api.constrains("product_id")
def check_product_is_not_kit(self):
# Bypasses the check regarding having orderpoints for phantom bom products
# in `mrp`
return True

Check warning on line 14 in sale_stock_mto_as_mts_orderpoint_mrp/models/stock_warehouse_orderpoint.py

View check run for this annotation

Codecov / codecov/patch

sale_stock_mto_as_mts_orderpoint_mrp/models/stock_warehouse_orderpoint.py#L14

Added line #L14 was not covered by tests
Empty file.
3 changes: 3 additions & 0 deletions sale_stock_mto_as_mts_orderpoint_mrp/readme/DESCRIPTION.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Glue module between Sale Stock MTO as MTS Orderpoint and MRP.

This allows to create orderpoints for Bills of Materials, and to set them as MTO.
Loading
Loading