Skip to content

Commit

Permalink
[ADD] sale_order_blanket_order, sale_order_blanket_order_stock_prebook
Browse files Browse the repository at this point in the history
  • Loading branch information
lmignon committed Dec 3, 2024
1 parent 21e5d23 commit f88bfcb
Show file tree
Hide file tree
Showing 47 changed files with 4,030 additions and 0 deletions.
222 changes: 222 additions & 0 deletions sale_order_blanket_order/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
==============
Sale Framework
==============

..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:d0b6a096d18178fbd15da557bf07466d1ff491c59a2b56a17781a6d020da21dd
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |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%2Fsale--workflow-lightgray.png?logo=github
:target: https://github.com/OCA/sale-workflow/tree/16.0/sale_order_blanket_order
: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_order_blanket_order
: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|

This module extends the functionality of Sale Order to support Blanket
Order and Call of Order.

Blanket Order
=============

A Blanket Order is a standard sales order with the following specific
features:

- Type: Classified as "Blanket Order".
- Defined Duration: Includes a validity period (end date).
- Payment Terms: Allows selection of preferred terms (e.g., 90 days end
of month, upon delivery, etc.).
- Invoicing Policy: Can be based on product settings or the order
itself.
- Stock Reservation: Allows advance reservation of sold quantities.
- Handling Unfulfilled Quantities: Provides options for dealing with
undelivered quantities upon order expiration.
- Prices are calculated based on existing rules since it is a standard
sales order type.

The blanket order serves as the central element triggering stock
management and invoicing mechanisms.

Stock Management
----------------

Delivered quantities are tracked on the sales order lines as with
regular sales orders. By default, the stock is not reserved upon
confirmation of the blanket order. This is achieved by using the OCA
module
`sale_manual_delivery <https://pypi.org/project/odoo-addon-sale-manual-delivery/>`__.
As a result, the stock will be reserved only when a call-off order is
created for the quantity to be delivered.

In some cases, you may want to reserve stock upon confirmation of the
blanket order. This can be achieved by using the OCA module
`sale_order_blanket_order_stock_prebook <https://pypi.org/project/odoo-addon-sale-order-blanket-order-stock-prebook/>`__.
This module extends the functionality of Sale Blanket Order to support
the reservation of stock for future consumption by call-off orders. The
reservation is done at the time of the blanket order confirmation for a
consumption starting at the validity start date of the blanket order.
This behavior can be configured on the blanket order.

Invoicing
---------

Standard invoicing policies apply (e.g., invoice on order or on
delivery). Payment terms are configurable per order. Prepayment can be
enforced by configuring the invoicing policy at the order level using
the OCA module
`sale_invoice_policy <https://pypi.org/project/odoo-addon-sale-invoice-policy/>`__.

Consumption Management
----------------------

A wizard will be available on the blanket order to initiate a delivery.
It allows users to select products and quantities for delivery. This
action creates a Call-off Order linked to the blanket order.

Call-off Order
==============

A Call-off Order is a standard sales order with these specific
characteristics:

- Type: Classified as "Call-off Order".
- Linked to Blanket Order: Only includes products from the blanket
order.
- Delivery Release: Enables the release of reserved stock for delivery.
- No Invoicing or Stock Management: These are handled via the linked
blanket order.

Stock Management
----------------

No delivery is generated directly from the call-off order.

It triggers:

- Release of the reserved quantity in the blanket order.
- Adjustment of stock reservations for the remaining quantities.

Standard Sales Orders
=====================

To support existing workflows (e.g., e-commerce), call-off orders can be
generated transparently from standard sales orders based on product and
availability:

Entire orders may be converted into call-off orders if all products are
linked to a blanket order. Mixed orders split call-off items into a new
call-off order, with both confirmed within the available quantities of
the blanket order.

**Table of contents**

.. contents::
:local:

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

When a company sells the same products to the same customers on a
regular basis, it's a common business practice to create a sale
framework that defines the terms and conditions of the sales.

If you need a way to define:

- the terms and conditions of the sales,
- the payment terms,
- the delivery terms,

and also secure the quantities of the products to be delivered, the sale
framework module is the right choice.

This module introduces 2 new kinkds of sale orders:

1. Sale Blanket Order: This is a sale order that defines the terms and
conditions of the sales, the payment terms, the delivery terms, and
secures the quantities of the products to be delivered. It is used to
create sale orders that will be delivered in the future.

2. Call of order: This is a sale order that is created to consume the
quantities of the products secured in the sale blanket order.

Others modules can be used to provide the same kind of features. For
example, the module
(sale_blanket_order)[`https://pypi.org/project/odoo-addon-sale-blanket-order] <https://pypi.org/project/odoo-addon-sale-blanket-order]>`__
also defines the concept of sale blanket order. The main difference
between the two modules is that the sale framework module extends the
sale order model to add the sale blanket order and the call of order.
This allows to keep the benefits of all the extensions made on the sale
order model by other modules without having to adapt them to the sale
blanket order model (discount, invoicing; inventory process, ...).

Usage
=====

By default, the automatic creation of call-off orders from normal sale
orders containing products part of a blanket order is disabled. To
enable this feature, you need to go into the sales settings and enable
the option "CCreate Call-Off from SO if possible".

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_order_blanket_order%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
-------

* ACSONE SA/NV
* BCIM

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

- Laurent Mignon\ [email protected] (https://www.acsone.eu)
- Jacques-Etienne Baudoux (BCIM) [email protected]

Other credits
-------------

The development of this module has been financially supported by:

- ALCYON Belux

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/sale-workflow <https://github.com/OCA/sale-workflow/tree/16.0/sale_order_blanket_order>`_ project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
2 changes: 2 additions & 0 deletions sale_order_blanket_order/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from . import models
from .hooks import pre_init_hook
21 changes: 21 additions & 0 deletions sale_order_blanket_order/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Copyright 2024 ACSONE SA/NV
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

{
"name": "Sale Framework",
"summary": """Manage blanket order and call of ordr""",
"version": "16.0.1.0.0",
"license": "AGPL-3",
"author": "ACSONE SA/NV,BCIM,Odoo Community Association (OCA)",
"website": "https://github.com/OCA/sale-workflow",
"depends": [
"sale_manual_delivery",
],
"data": [
"views/sale_order.xml",
"views/sale_order_line.xml",
"views/res_config_settings.xml",
],
"demo": [],
"pre_init_hook": "pre_init_hook",
}
34 changes: 34 additions & 0 deletions sale_order_blanket_order/hooks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import logging

_logger = logging.getLogger(__name__)


def pre_init_hook(cr):
_logger.info("Create column order_type in sale_order with default value 'normal'")
cr.execute(
"ALTER TABLE sale_order ADD COLUMN order_type varchar(255) DEFAULT 'normal'"
)
# drop the default value since it was only used to fill the column in existing records
cr.execute("ALTER TABLE sale_order ALTER COLUMN order_type DROP DEFAULT")

_logger.info(
"Create column order_type in sale_order_line with default value 'normal'"
)
cr.execute(
"ALTER TABLE sale_order_line ADD COLUMN order_type varchar(255) DEFAULT 'normal'"
)
# drop the default value since it was only used to fill the column in existing records
cr.execute("ALTER TABLE sale_order_line ALTER COLUMN order_type DROP DEFAULT")

# avoid computing the field for all records at module install
cr.execute(
"ALTER TABLE sale_order_line ADD COLUMN call_off_remaining_qty double precision"
)
cr.execute(
"ALTER TABLE sale_order_line ADD COLUMN blanket_validity_start_date date"
)
cr.execute("ALTER TABLE sale_order_line ADD COLUMN blanket_validity_end_date date")
cr.execute("ALTER TABLE sale_order_line ADD COLUMN blanket_order_id integer")
cr.execute(
"ALTER TABLE sale_order ADD COLUMN blanket_reservation_strategy varchar(255)"
)
6 changes: 6 additions & 0 deletions sale_order_blanket_order/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from . import res_company
from . import res_config_settings
from . import sale_order
from . import sale_order_line
from . import stock_move
from . import stock_rule
15 changes: 15 additions & 0 deletions sale_order_blanket_order/models/res_company.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Copyright 2024 ACSONE SA/NV
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

from odoo import fields, models


class ResCompany(models.Model):
_inherit = "res.company"

create_call_off_from_so_if_possible = fields.Boolean(
string="Create Call-Off from SO if possible",
help="If checked, when a sale order is confirmed and some lines refer to a "
"blanket order, these lines will be automatically moved to a new call-off "
"order.",
)
17 changes: 17 additions & 0 deletions sale_order_blanket_order/models/res_config_settings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Copyright 2024 ACSONE SA/NV
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

from odoo import fields, models


class ResConfigSettings(models.TransientModel):
_inherit = "res.config.settings"

create_call_off_from_so_if_possible = fields.Boolean(
related="company_id.create_call_off_from_so_if_possible",
readonly=False,
string="Create Call-Off from SO if possible",
help="If checked, when a sale order is confirmed and some lines refer to a "
"blanket order, these lines will be automatically moved to a new call-off "
"order.",
)
Loading

0 comments on commit f88bfcb

Please sign in to comment.