diff --git a/setup/website_sale_stock_available/odoo/addons/website_sale_stock_available b/setup/website_sale_stock_available/odoo/addons/website_sale_stock_available new file mode 120000 index 0000000000..0a728b0e9c --- /dev/null +++ b/setup/website_sale_stock_available/odoo/addons/website_sale_stock_available @@ -0,0 +1 @@ +../../../../website_sale_stock_available \ No newline at end of file diff --git a/setup/website_sale_stock_available/setup.py b/setup/website_sale_stock_available/setup.py new file mode 100644 index 0000000000..28c57bb640 --- /dev/null +++ b/setup/website_sale_stock_available/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +) diff --git a/website_sale_stock_available/README.rst b/website_sale_stock_available/README.rst new file mode 100644 index 0000000000..966698ba1b --- /dev/null +++ b/website_sale_stock_available/README.rst @@ -0,0 +1,120 @@ +============================ +Website Sale Stock Available +============================ + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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%2Fe--commerce-lightgray.png?logo=github + :target: https://github.com/OCA/e-commerce/tree/15.0/website_sale_stock_available + :alt: OCA/e-commerce +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/e-commerce-15-0/e-commerce-15-0-website_sale_stock_available + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png + :target: https://runbot.odoo-community.org/runbot/113/15.0 + :alt: Try me on Runbot + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module extends the functionality of the *Product Availability* module +(technical name: ``website_sale_stock``) so that for the eCommerce the *Available* +quantity of a product is taken into account instead of the *free* quantity. + +Note that in the past the eCommerce availability was based in *Forecasted quantity*. This +isn't true anymore from version 15.0. + +If a product is configured to *prevent sales if not enough stock* +(see configuration section) and its page is accessed in the Website Shop, +the availability messages will be based on the *Available* quantity instead of +*Free* quantity. And also, the eCommerce won't allow you to buy more products than +*Available* quantity (not *Free* quantity isn't taken into account). + +**Table of contents** + +.. contents:: + :local: + +Configuration +============= + +To configure this module, you need to: + +#. Go to *Inventory > Master Data > Products* and edit a product that + you only want to sell in the eCommerce if there is enough stock. +#. Navigate to *Out-of-stock (continue selling)* field in the *Sales* tab and unset it. +#. Go to *Inventory > Configuration > Settings*, navigate to *Stock available + to promise* section and set the desired option (you might need extra modules). If you + do not choose any, the value of *Available* quantity will be equal to *Forecasted* + quantity. + +Usage +===== + +To use this module, you need to: + +#. Go to your eCommerce. +#. Select a product that you has been previously configured to *prevent sales + if not enough stock* for the web product page. +#. Odoo doesn't allow you to add the product to the cart if *Available* + quantity (not *Free to use* quantity) is equal or less than zero. + Besides, availability messages will be based on the *Available* + quantity instead of the *Free to use* quantity. + +.. image:: https://raw.githubusercontent.com/OCA/e-commerce/15.0/website_sale_stock_available/static/description/availability_message.png + :width: 600 px + :alt: Availability message + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* Tecnativa + +Contributors +~~~~~~~~~~~~ + +* `Tecnativa `_: + + * Ernesto Tejeda + * Pedro M. Baeza + * David Vidal + +* Iván Todorovich + +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/e-commerce `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/website_sale_stock_available/__init__.py b/website_sale_stock_available/__init__.py new file mode 100644 index 0000000000..df9b9c226b --- /dev/null +++ b/website_sale_stock_available/__init__.py @@ -0,0 +1,3 @@ +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from . import controllers +from . import models diff --git a/website_sale_stock_available/__manifest__.py b/website_sale_stock_available/__manifest__.py new file mode 100644 index 0000000000..ed7fd2080c --- /dev/null +++ b/website_sale_stock_available/__manifest__.py @@ -0,0 +1,18 @@ +# Copyright 2020 Tecnativa - Ernesto Tejeda +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +{ + "name": "Website Sale Stock Available", + "summary": "Display 'Available to promise' in shop online instead " + "of 'Free To Use Quantity'", + "version": "16.0.1.0.0", + "category": "Website", + "website": "https://github.com/OCA/e-commerce", + "author": "Tecnativa, Odoo Community Association (OCA)", + "license": "AGPL-3", + "depends": [ + "stock_available", + "website_sale_stock", + ], + "data": [], + "installable": True, +} diff --git a/website_sale_stock_available/controllers/__init__.py b/website_sale_stock_available/controllers/__init__.py new file mode 100644 index 0000000000..12a7e529b6 --- /dev/null +++ b/website_sale_stock_available/controllers/__init__.py @@ -0,0 +1 @@ +from . import main diff --git a/website_sale_stock_available/controllers/main.py b/website_sale_stock_available/controllers/main.py new file mode 100644 index 0000000000..9fd425c736 --- /dev/null +++ b/website_sale_stock_available/controllers/main.py @@ -0,0 +1,15 @@ +# Copyright 2020 Tecnativa - David Vidal +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from odoo.http import request, route + +from odoo.addons.website_sale_stock.controllers.main import PaymentPortal + + +class PaymentPortal(PaymentPortal): + @route() + def shop_payment_transaction(self, *args, **kwargs): + """Inject a context when potential or promised stock is set""" + request.website = request.website.with_context( + website_sale_stock_available=True + ) + return super().shop_payment_transaction(*args, **kwargs) diff --git a/website_sale_stock_available/i18n/ca.po b/website_sale_stock_available/i18n/ca.po new file mode 100644 index 0000000000..f36f7024b8 --- /dev/null +++ b/website_sale_stock_available/i18n/ca.po @@ -0,0 +1,35 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * website_sale_stock_available +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2021-01-20 20:45+0000\n" +"Last-Translator: claudiagn \n" +"Language-Team: none\n" +"Language: ca\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.3.2\n" + +#. module: website_sale_stock_available +#: model:ir.model,name:website_sale_stock_available.model_sale_order +msgid "Allowing sale_order_type to work with website_sale." +msgstr "" + +#. module: website_sale_stock_available +#: model:ir.model,name:website_sale_stock_available.model_product_product +msgid "Product" +msgstr "Producte" + +#. module: website_sale_stock_available +#: model:ir.model,name:website_sale_stock_available.model_product_template +msgid "Product Template" +msgstr "Plantilla de producte" + +#~ msgid "Sale Order" +#~ msgstr "Comanda de venda" diff --git a/website_sale_stock_available/i18n/es.po b/website_sale_stock_available/i18n/es.po new file mode 100644 index 0000000000..893a8cb2eb --- /dev/null +++ b/website_sale_stock_available/i18n/es.po @@ -0,0 +1,35 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * website_sale_stock_available +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2020-11-03 13:08+0000\n" +"Last-Translator: claudiagn \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 3.10\n" + +#. module: website_sale_stock_available +#: model:ir.model,name:website_sale_stock_available.model_sale_order +msgid "Allowing sale_order_type to work with website_sale." +msgstr "" + +#. module: website_sale_stock_available +#: model:ir.model,name:website_sale_stock_available.model_product_product +msgid "Product" +msgstr "Producto" + +#. module: website_sale_stock_available +#: model:ir.model,name:website_sale_stock_available.model_product_template +msgid "Product Template" +msgstr "Plantilla de producto" + +#~ msgid "Sale Order" +#~ msgstr "Pedido de venta" diff --git a/website_sale_stock_available/i18n/es_AR.po b/website_sale_stock_available/i18n/es_AR.po new file mode 100644 index 0000000000..92e9c46144 --- /dev/null +++ b/website_sale_stock_available/i18n/es_AR.po @@ -0,0 +1,44 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * website_sale_stock_available +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2021-09-11 19:33+0000\n" +"Last-Translator: Ignacio Buioli \n" +"Language-Team: none\n" +"Language: es_AR\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.3.2\n" + +#. module: website_sale_stock_available +#: model:ir.model,name:website_sale_stock_available.model_sale_order +msgid "Allowing sale_order_type to work with website_sale." +msgstr "" + +#. module: website_sale_stock_available +#: model:ir.model,name:website_sale_stock_available.model_product_product +msgid "Product" +msgstr "Producto" + +#. module: website_sale_stock_available +#: model:ir.model,name:website_sale_stock_available.model_product_template +msgid "Product Template" +msgstr "Plantilla de Producto" + +#~ msgid "Display Name" +#~ msgstr "Mostrar Nombre" + +#~ msgid "ID" +#~ msgstr "ID" + +#~ msgid "Last Modified on" +#~ msgstr "Última modificación en" + +#~ msgid "Sales Order" +#~ msgstr "Pedidos de Ventas" diff --git a/website_sale_stock_available/i18n/es_CL.po b/website_sale_stock_available/i18n/es_CL.po new file mode 100644 index 0000000000..378df2439f --- /dev/null +++ b/website_sale_stock_available/i18n/es_CL.po @@ -0,0 +1,35 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * website_sale_stock_available +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2020-05-30 05:19+0000\n" +"Last-Translator: Nelson Ramírez Sánchez \n" +"Language-Team: none\n" +"Language: es_CL\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 3.10\n" + +#. module: website_sale_stock_available +#: model:ir.model,name:website_sale_stock_available.model_sale_order +msgid "Allowing sale_order_type to work with website_sale." +msgstr "" + +#. module: website_sale_stock_available +#: model:ir.model,name:website_sale_stock_available.model_product_product +msgid "Product" +msgstr "Producto" + +#. module: website_sale_stock_available +#: model:ir.model,name:website_sale_stock_available.model_product_template +msgid "Product Template" +msgstr "Plantilla de Producto" + +#~ msgid "Sale Order" +#~ msgstr "Nota de Venta" diff --git a/website_sale_stock_available/i18n/fr.po b/website_sale_stock_available/i18n/fr.po new file mode 100644 index 0000000000..b06b91555f --- /dev/null +++ b/website_sale_stock_available/i18n/fr.po @@ -0,0 +1,35 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * website_sale_stock_available +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2020-11-23 15:36+0000\n" +"Last-Translator: Yann Papouin \n" +"Language-Team: none\n" +"Language: fr\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 3.10\n" + +#. module: website_sale_stock_available +#: model:ir.model,name:website_sale_stock_available.model_sale_order +msgid "Allowing sale_order_type to work with website_sale." +msgstr "" + +#. module: website_sale_stock_available +#: model:ir.model,name:website_sale_stock_available.model_product_product +msgid "Product" +msgstr "Article" + +#. module: website_sale_stock_available +#: model:ir.model,name:website_sale_stock_available.model_product_template +msgid "Product Template" +msgstr "Modèle d'article" + +#~ msgid "Sale Order" +#~ msgstr "Commande client" diff --git a/website_sale_stock_available/i18n/nl.po b/website_sale_stock_available/i18n/nl.po new file mode 100644 index 0000000000..525927c671 --- /dev/null +++ b/website_sale_stock_available/i18n/nl.po @@ -0,0 +1,35 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * website_sale_stock_available +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2020-12-15 13:19+0000\n" +"Last-Translator: Bosd \n" +"Language-Team: none\n" +"Language: nl\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.3.2\n" + +#. module: website_sale_stock_available +#: model:ir.model,name:website_sale_stock_available.model_sale_order +msgid "Allowing sale_order_type to work with website_sale." +msgstr "" + +#. module: website_sale_stock_available +#: model:ir.model,name:website_sale_stock_available.model_product_product +msgid "Product" +msgstr "Product" + +#. module: website_sale_stock_available +#: model:ir.model,name:website_sale_stock_available.model_product_template +msgid "Product Template" +msgstr "Product Sjabloon" + +#~ msgid "Sale Order" +#~ msgstr "Verkoop order" diff --git a/website_sale_stock_available/i18n/website_sale_stock_available.pot b/website_sale_stock_available/i18n/website_sale_stock_available.pot new file mode 100644 index 0000000000..5cbcc4cdef --- /dev/null +++ b/website_sale_stock_available/i18n/website_sale_stock_available.pot @@ -0,0 +1,29 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * website_sale_stock_available +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 15.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: website_sale_stock_available +#: model:ir.model,name:website_sale_stock_available.model_sale_order +msgid "Allowing sale_order_type to work with website_sale." +msgstr "" + +#. module: website_sale_stock_available +#: model:ir.model,name:website_sale_stock_available.model_product_product +msgid "Product" +msgstr "" + +#. module: website_sale_stock_available +#: model:ir.model,name:website_sale_stock_available.model_product_template +msgid "Product Template" +msgstr "" diff --git a/website_sale_stock_available/models/__init__.py b/website_sale_stock_available/models/__init__.py new file mode 100644 index 0000000000..5486cb6719 --- /dev/null +++ b/website_sale_stock_available/models/__init__.py @@ -0,0 +1,5 @@ +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + +from . import product_product +from . import product_template +from . import sale_order diff --git a/website_sale_stock_available/models/product_product.py b/website_sale_stock_available/models/product_product.py new file mode 100644 index 0000000000..fd46c2dd28 --- /dev/null +++ b/website_sale_stock_available/models/product_product.py @@ -0,0 +1,20 @@ +# Copyright 2020 Tecnativa - Ernesto Tejeda +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import models + + +class Product(models.Model): + _inherit = "product.product" + + def _compute_quantities_dict( + self, lot_id, owner_id, package_id, from_date=False, to_date=False + ): + res = super()._compute_quantities_dict( + lot_id, owner_id, package_id, from_date, to_date + ) + if self.env.context.get("website_sale_stock_available"): + for product in self.with_context(website_sale_stock_available=False): + immediately = product.immediately_usable_qty + res[product.id]["free_qty"] = immediately + return res diff --git a/website_sale_stock_available/models/product_template.py b/website_sale_stock_available/models/product_template.py new file mode 100644 index 0000000000..28d0173738 --- /dev/null +++ b/website_sale_stock_available/models/product_template.py @@ -0,0 +1,27 @@ +# Copyright 2020 Tecnativa - Ernesto Tejeda +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import models + + +class ProductTemplate(models.Model): + _inherit = "product.template" + + def _get_combination_info( + self, + combination=False, + product_id=False, + add_qty=1, + pricelist=False, + parent_combination=False, + only_template=False, + ): + template = self.with_context(website_sale_stock_available=True) + return super(ProductTemplate, template)._get_combination_info( + combination, + product_id, + add_qty, + pricelist, + parent_combination, + only_template, + ) diff --git a/website_sale_stock_available/models/sale_order.py b/website_sale_stock_available/models/sale_order.py new file mode 100644 index 0000000000..92da2d06d2 --- /dev/null +++ b/website_sale_stock_available/models/sale_order.py @@ -0,0 +1,16 @@ +# Copyright 2020 Tecnativa - Ernesto Tejeda +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import models + + +class SaleOrder(models.Model): + _inherit = "sale.order" + + def _cart_update( + self, product_id=None, line_id=None, add_qty=0, set_qty=0, **kwargs + ): + order = self.with_context(website_sale_stock_available=True) + return super(SaleOrder, order)._cart_update( + product_id, line_id, add_qty, set_qty, **kwargs + ) diff --git a/website_sale_stock_available/readme/CONFIGURE.rst b/website_sale_stock_available/readme/CONFIGURE.rst new file mode 100644 index 0000000000..d42c0f9c89 --- /dev/null +++ b/website_sale_stock_available/readme/CONFIGURE.rst @@ -0,0 +1,9 @@ +To configure this module, you need to: + +#. Go to *Inventory > Master Data > Products* and edit a product that + you only want to sell in the eCommerce if there is enough stock. +#. Navigate to *Out-of-stock (continue selling)* field in the *Sales* tab and unset it. +#. Go to *Inventory > Configuration > Settings*, navigate to *Stock available + to promise* section and set the desired option (you might need extra modules). If you + do not choose any, the value of *Available* quantity will be equal to *Forecasted* + quantity. diff --git a/website_sale_stock_available/readme/CONTRIBUTORS.rst b/website_sale_stock_available/readme/CONTRIBUTORS.rst new file mode 100644 index 0000000000..837b815bb1 --- /dev/null +++ b/website_sale_stock_available/readme/CONTRIBUTORS.rst @@ -0,0 +1,7 @@ +* `Tecnativa `_: + + * Ernesto Tejeda + * Pedro M. Baeza + * David Vidal + +* Iván Todorovich diff --git a/website_sale_stock_available/readme/DESCRIPTION.rst b/website_sale_stock_available/readme/DESCRIPTION.rst new file mode 100644 index 0000000000..f17a79c810 --- /dev/null +++ b/website_sale_stock_available/readme/DESCRIPTION.rst @@ -0,0 +1,12 @@ +This module extends the functionality of the *Product Availability* module +(technical name: ``website_sale_stock``) so that for the eCommerce the *Available* +quantity of a product is taken into account instead of the *free* quantity. + +Note that in the past the eCommerce availability was based in *Forecasted quantity*. This +isn't true anymore from version 15.0. + +If a product is configured to *prevent sales if not enough stock* +(see configuration section) and its page is accessed in the Website Shop, +the availability messages will be based on the *Available* quantity instead of +*Free* quantity. And also, the eCommerce won't allow you to buy more products than +*Available* quantity (not *Free* quantity isn't taken into account). diff --git a/website_sale_stock_available/readme/USAGE.rst b/website_sale_stock_available/readme/USAGE.rst new file mode 100644 index 0000000000..2a1e3aa99a --- /dev/null +++ b/website_sale_stock_available/readme/USAGE.rst @@ -0,0 +1,13 @@ +To use this module, you need to: + +#. Go to your eCommerce. +#. Select a product that you has been previously configured to *prevent sales + if not enough stock* for the web product page. +#. Odoo doesn't allow you to add the product to the cart if *Available* + quantity (not *Free to use* quantity) is equal or less than zero. + Besides, availability messages will be based on the *Available* + quantity instead of the *Free to use* quantity. + +.. image:: ../static/description/availability_message.png + :width: 600 px + :alt: Availability message diff --git a/website_sale_stock_available/static/description/availability_message.png b/website_sale_stock_available/static/description/availability_message.png new file mode 100644 index 0000000000..61b61318d2 Binary files /dev/null and b/website_sale_stock_available/static/description/availability_message.png differ diff --git a/website_sale_stock_available/static/description/icon.png b/website_sale_stock_available/static/description/icon.png new file mode 100644 index 0000000000..06c0dd0c4c Binary files /dev/null and b/website_sale_stock_available/static/description/icon.png differ diff --git a/website_sale_stock_available/static/description/index.html b/website_sale_stock_available/static/description/index.html new file mode 100644 index 0000000000..c2d427b040 --- /dev/null +++ b/website_sale_stock_available/static/description/index.html @@ -0,0 +1,463 @@ + + + + + + +Website Sale Stock Available + + + +
+

Website Sale Stock Available

+ + +

Beta License: AGPL-3 OCA/e-commerce Translate me on Weblate Try me on Runbot

+

This module extends the functionality of the Product Availability module +(technical name: website_sale_stock) so that for the eCommerce the Available +quantity of a product is taken into account instead of the free quantity.

+

Note that in the past the eCommerce availability was based in Forecasted quantity. This +isn’t true anymore from version 15.0.

+

If a product is configured to prevent sales if not enough stock +(see configuration section) and its page is accessed in the Website Shop, +the availability messages will be based on the Available quantity instead of +Free quantity. And also, the eCommerce won’t allow you to buy more products than +Available quantity (not Free quantity isn’t taken into account).

+

Table of contents

+ +
+

Configuration

+

To configure this module, you need to:

+
    +
  1. Go to Inventory > Master Data > Products and edit a product that +you only want to sell in the eCommerce if there is enough stock.
  2. +
  3. Navigate to Out-of-stock (continue selling) field in the Sales tab and unset it.
  4. +
  5. Go to Inventory > Configuration > Settings, navigate to Stock available +to promise section and set the desired option (you might need extra modules). If you +do not choose any, the value of Available quantity will be equal to Forecasted +quantity.
  6. +
+
+
+

Usage

+

To use this module, you need to:

+
    +
  1. Go to your eCommerce.
  2. +
  3. Select a product that you has been previously configured to prevent sales +if not enough stock for the web product page.
  4. +
  5. Odoo doesn’t allow you to add the product to the cart if Available +quantity (not Free to use quantity) is equal or less than zero. +Besides, availability messages will be based on the Available +quantity instead of the Free to use quantity.
  6. +
+Availability message +
+
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • Tecnativa
  • +
+
+
+

Contributors

+
    +
  • Tecnativa:
      +
    • Ernesto Tejeda
    • +
    • Pedro M. Baeza
    • +
    • David Vidal
    • +
    +
  • +
  • Iván Todorovich
  • +
+
+
+

Maintainers

+

This module is maintained by the OCA.

+Odoo Community Association +

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/e-commerce project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+ + diff --git a/website_sale_stock_available/tests/__init__.py b/website_sale_stock_available/tests/__init__.py new file mode 100644 index 0000000000..59a5546ae0 --- /dev/null +++ b/website_sale_stock_available/tests/__init__.py @@ -0,0 +1,3 @@ +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + +from . import test_website_sale_stock_available diff --git a/website_sale_stock_available/tests/test_website_sale_stock_available.py b/website_sale_stock_available/tests/test_website_sale_stock_available.py new file mode 100644 index 0000000000..d594839bea --- /dev/null +++ b/website_sale_stock_available/tests/test_website_sale_stock_available.py @@ -0,0 +1,91 @@ +# Copyright 2020 Tecnativa - Ernesto Tejeda +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + +from odoo.tests.common import TransactionCase + + +class SaleStockAvailableInfoPopup(TransactionCase): + @classmethod + def setUpClass(cls): + super(SaleStockAvailableInfoPopup, cls).setUpClass() + user_group_stock_user = cls.env.ref("stock.group_stock_user") + cls.user_stock_user = cls.env["res.users"].create( + { + "name": "Pauline Poivraisselle", + "login": "pauline", + "email": "p.p@example.com", + "notification_type": "inbox", + "groups_id": [(6, 0, [user_group_stock_user.id])], + } + ) + cls.product = cls.env["product.product"].create( + { + "name": "Storable product", + "type": "product", + } + ) + cls.stock_location = cls.env.ref("stock.stock_location_stock") + cls.customers_location = cls.env.ref("stock.stock_location_customers") + cls.suppliers_location = cls.env.ref("stock.stock_location_suppliers") + cls.env["stock.quant"].create( + { + "product_id": cls.product.id, + "location_id": cls.stock_location.id, + "quantity": 40.0, + } + ) + cls.picking_out = cls.env["stock.picking"].create( + { + "picking_type_id": cls.env.ref("stock.picking_type_out").id, + "location_id": cls.stock_location.id, + "location_dest_id": cls.customers_location.id, + } + ) + cls.env["stock.move"].create( + { + "name": "a move", + "product_id": cls.product.id, + "product_uom_qty": 3.0, + "product_uom": cls.product.uom_id.id, + "picking_id": cls.picking_out.id, + "location_id": cls.stock_location.id, + "location_dest_id": cls.customers_location.id, + } + ) + cls.picking_in = cls.env["stock.picking"].create( + { + "picking_type_id": cls.env.ref("stock.picking_type_in").id, + "location_id": cls.suppliers_location.id, + "location_dest_id": cls.stock_location.id, + } + ) + cls.env["stock.move"].create( + { + "restrict_partner_id": cls.user_stock_user.partner_id.id, + "name": "another move", + "product_id": cls.product.id, + "product_uom_qty": 5.0, + "product_uom": cls.product.uom_id.id, + "picking_id": cls.picking_in.id, + "location_id": cls.suppliers_location.id, + "location_dest_id": cls.stock_location.id, + } + ) + + def test_get_combination_info(self): + product_tmpl = self.product.product_tmpl_id + combination_info = product_tmpl.with_context( + website_sale_stock_get_quantity=True, + )._get_combination_info() + self.assertEqual( + combination_info["free_qty"], + 40, + ) + self.picking_out.action_confirm() + self.picking_in.action_assign() + combination_info = product_tmpl.with_context( + website_sale_stock_get_quantity=True, + )._get_combination_info() + self.assertEqual( + combination_info["free_qty"], self.product.immediately_usable_qty + )