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] sale_stock_prebook #3423

Open
wants to merge 4 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
93 changes: 93 additions & 0 deletions sale_stock_prebook/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
==================
sale_stock_prebook
==================

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

.. |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-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/16.0/sale_stock_prebook
: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-16-0/sale-workflow-16-0-sale_stock_prebook
: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=16.0
:alt: Try me on Runboat

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

Add process to prebook a sale order's stock before confirming it

**Table of contents**

.. contents::
:local:

Usage
=====

On the sale.order view you will find two new buttons "Reserve Stock" and "Release reservation"
which are only shown if the state is in "Quotation" or "Quotation Sent".

The reservation creates the picking/moves via a procurement run by placing a real move.

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_stock_prebook%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
~~~~~~~

* MT Software
* BCIM

Contributors
~~~~~~~~~~~~

* Michael Tietz (MT Software) <[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.

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

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

|maintainer-mt-software-de|

This module is part of the `OCA/sale-workflow <https://github.com/OCA/sale-workflow/tree/16.0/sale_stock_prebook>`_ 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_prebook/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import models
18 changes: 18 additions & 0 deletions sale_stock_prebook/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Copyright 2023 Michael Tietz (MT Software) <[email protected]>
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
{
"name": "sale_stock_prebook",
"summary": "Add process to prebook a sale order's stock before confirming it",
"version": "16.0.1.0.0",
"author": "MT Software, BCIM, Odoo Community Association (OCA)",
"website": "https://github.com/OCA/sale-workflow",
"data": [
"views/sale_views.xml",
"views/stock_route_views.xml",
],
"depends": [
"sale_stock",
],
"maintainers": ["mt-software-de"],
"license": "LGPL-3",
}
5 changes: 5 additions & 0 deletions sale_stock_prebook/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from . import sale
from . import stock_move
from . import stock_rule
from . import report_stock_forecasted
from . import stock_route
13 changes: 13 additions & 0 deletions sale_stock_prebook/models/report_stock_forecasted.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Copyright 2023 Michael Tietz (MT Software) <[email protected]>
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
from odoo import models
from odoo.osv import expression


class ReplenishmentReport(models.AbstractModel):
_inherit = "report.stock.report_product_product_replenishment"

def _product_sale_domain(self, product_template_ids, product_variant_ids):
domain = super()._product_sale_domain(product_template_ids, product_variant_ids)
domain = expression.AND([domain, [("order_id.stock_is_reserved", "=", False)]])
return domain

Check warning on line 13 in sale_stock_prebook/models/report_stock_forecasted.py

View check run for this annotation

Codecov / codecov/patch

sale_stock_prebook/models/report_stock_forecasted.py#L11-L13

Added lines #L11 - L13 were not covered by tests
110 changes: 110 additions & 0 deletions sale_stock_prebook/models/sale.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
# Copyright 2023 Michael Tietz (MT Software) <[email protected]>
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
from odoo import api, fields, models


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

def _prepare_reserve_procurement_values(self, group_id=None):
values = self._prepare_procurement_values(group_id)
values["used_for_sale_reservation"] = True
return values

def _should_prebook_stock(self):
"""Checks if SOL product has no_sale_stock_prebook set
to know if we need to reserve it or not"""
self.ensure_one()
for route in self.product_id.route_ids:
if route.no_sale_stock_prebook:
return False
return True

def _prepare_reserve_procurement(self, group):
"""Adjusts UOM qty for product, makes list of field values for
procurement group"""
product_qty, procurement_uom = self.product_uom._adjust_uom_quantities(
self.product_uom_qty, self.product_id.uom_id
)
return self.env["procurement.group"].Procurement(
self.product_id,
product_qty,
procurement_uom,
self.order_id.partner_shipping_id.property_stock_customer,
self.product_id.display_name,
group.name,
self.order_id.company_id,
self._prepare_reserve_procurement_values(group_id=group),
)

def _prepare_reserve_procurements(self, group):
"""Prepares list of dicts - reserve procurements"""
procurements = []
for line in self:
if not line._should_prebook_stock():
continue
procurements.append(line._prepare_reserve_procurement(group))
return procurements


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

stock_is_reserved = fields.Boolean(
"Stock is reserved",
compute="_compute_stock_is_reserved",
store=True,
)

def _get_reservation_pickings(self):
return self.picking_ids.filtered(
lambda p: any(m.used_for_sale_reservation for m in p.move_ids)
)

@api.depends("picking_ids.move_ids.used_for_sale_reservation")
def _compute_stock_is_reserved(self):
for rec in self:
rec.stock_is_reserved = (rec._get_reservation_pickings() and True) or False

def _action_cancel(self):
self.release_reservation()
return super()._action_cancel()

def _action_confirm(self):
self.release_reservation()
return super()._action_confirm()

def _prepare_reserve_procurement_group_values(self):
self.ensure_one()
values = self.order_line[0]._prepare_procurement_group_vals()
values["name"] = f"Reservation for {values['name']}"
return values

def _create_reserve_procurement_group(self):
return self.env["procurement.group"].create(
self._prepare_reserve_procurement_group_values()
)

def reserve_stock(self):
self = self.filtered(
lambda s: not s.stock_is_reserved
and s.state in ["draft", "sent"]
or not s.order_line
)
if not self:
return

Check warning on line 95 in sale_stock_prebook/models/sale.py

View check run for this annotation

Codecov / codecov/patch

sale_stock_prebook/models/sale.py#L95

Added line #L95 was not covered by tests

self = self.with_context(sale_stock_prebook_stop_proc_run=True)
procurements = []

for order in self:
group = order._create_reserve_procurement_group()
procurements += order.order_line._prepare_reserve_procurements(group)
if procurements:
self.env["procurement.group"].run(procurements)

def release_reservation(self):
pickings = self._get_reservation_pickings()
pickings.action_cancel()
pickings.group_id.sudo().unlink()
pickings.sudo().unlink()
24 changes: 24 additions & 0 deletions sale_stock_prebook/models/stock_move.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Copyright 2023 Michael Tietz (MT Software) <[email protected]>
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
from odoo import _, api, fields, models
from odoo.exceptions import ValidationError


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

used_for_sale_reservation = fields.Boolean(default=False)

@api.constrains("used_for_sale_reservation", "quantity_done")
def _check_used_for_sale_reservation(self):
for move in self:
if move.used_for_sale_reservation and move.quantity_done:
raise ValidationError(
_(
"You cannot set a quantity done on a move used for sale reservation"
)
)

def _action_assign(self, force_qty=None):
self = self.filtered(lambda m: not m.used_for_sale_reservation)
return super(StockMove, self)._action_assign(force_qty=force_qty)
11 changes: 11 additions & 0 deletions sale_stock_prebook/models/stock_route.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Copyright 2023 Raumschmiede GmbH
from odoo import fields, models


class StockRoute(models.Model):
_inherit = "stock.route"

no_sale_stock_prebook = fields.Boolean(
help="If set no stock will be prebooked, "
"for configured Products with this route",
)
21 changes: 21 additions & 0 deletions sale_stock_prebook/models/stock_rule.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Copyright 2023 Michael Tietz (MT Software) <[email protected]>
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
from odoo import models


class StockRule(models.Model):
_inherit = "stock.rule"

def _get_custom_move_fields(self):
res = super()._get_custom_move_fields()
res.append("used_for_sale_reservation")
return res

def _run_pull(self, procurements):
if not self.env.context.get("sale_stock_prebook_stop_proc_run"):
return super()._run_pull(procurements)
actions_to_run = []
for procurement, rule in procurements:
if rule.picking_type_id.code == "outgoing":
actions_to_run.append((procurement, rule))
super()._run_pull(actions_to_run)
1 change: 1 addition & 0 deletions sale_stock_prebook/readme/CONTRIBUTORS.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* Michael Tietz (MT Software) <[email protected]>
1 change: 1 addition & 0 deletions sale_stock_prebook/readme/DESCRIPTION.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add process to prebook a sale order's stock before confirming it
4 changes: 4 additions & 0 deletions sale_stock_prebook/readme/USAGE.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
On the sale.order view you will find two new buttons "Reserve Stock" and "Release reservation"
which are only shown if the state is in "Quotation" or "Quotation Sent".

The reservation creates the picking/moves via a procurement run by placing a real move.
Loading
Loading