diff --git a/.pylintrc b/.pylintrc index a6fbb3e..f28e124 100644 --- a/.pylintrc +++ b/.pylintrc @@ -7,7 +7,7 @@ readme-template-url="https://github.com/OCA/maintainer-tools/blob/master/templat manifest-required-authors=BAKEUP manifest-required-keys=license manifest-deprecated-keys=description,active -license-allowed=LGPL-3,OPL-1 +license-allowed=LGPL-3,OPL-1,AGPL-3 valid-odoo-versions=16.0 [MESSAGES CONTROL] diff --git a/website_decimal_quantity/README.rst b/website_decimal_quantity/README.rst new file mode 100644 index 0000000..76bd763 --- /dev/null +++ b/website_decimal_quantity/README.rst @@ -0,0 +1,69 @@ +======================== +Website Decimal Quantity +======================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:57abd0a526646836d53d961ac63f79f774c0b591a63f96fcc61f9fb0ec6e196d + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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-bruecksen%2Fife_nfu-lightgray.png?logo=github + :target: https://github.com/bruecksen/ife_nfu/tree/16.0/website_decimal_quantity + :alt: bruecksen/ife_nfu + +|badge1| |badge2| |badge3| + +The app allows to select quantity in decimal for products in Website/Shop", + "description": """ + The app allows to select quantity in decimal for products in Website/Shop + +**Table of contents** + +.. contents:: + :local: + +Changelog +========= + +- 16.0.1.0.0: Initial version + +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 to smash it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* Cybrosys Techno Solutions +* BAKEUP + +Contributors +~~~~~~~~~~~~ + +- Cybrosys Techno Solutions +- BAKEUP + +Maintainers +~~~~~~~~~~~ + +This module is part of the `bruecksen/ife_nfu `_ project on GitHub. + +You are welcome to contribute. diff --git a/website_decimal_quantity/__init__.py b/website_decimal_quantity/__init__.py new file mode 100644 index 0000000..d439daa --- /dev/null +++ b/website_decimal_quantity/__init__.py @@ -0,0 +1,22 @@ +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2023-TODAY Cybrosys Technologies(). +# Author: Vivek @ cybrosys,(odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU AFFERO +# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. +# +# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE +# (AGPL v3) along with this program. +# If not, see . +# +############################################################################# +from . import controllers +from . import models diff --git a/website_decimal_quantity/__manifest__.py b/website_decimal_quantity/__manifest__.py new file mode 100644 index 0000000..c355d43 --- /dev/null +++ b/website_decimal_quantity/__manifest__.py @@ -0,0 +1,43 @@ +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2023-TODAY Cybrosys Technologies(). +# Author: Vivek @ cybrosys,(odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU AFFERO +# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. +# +# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE +# (AGPL v3) along with this program. +# If not, see . +# +############################################################################# +{ + "name": "Website Decimal Quantity", + "version": "16.0.1.0.0", + "category": "Website/Website", + "author": "Cybrosys Techno Solutions,BAKEUP", + "company": "Cybrosys Techno Solutions", + "maintainer": "BAKEUP", + "images": ["static/description/banner.png"], + "website": "https://www.bakeup.org", + "depends": ["website_sale"], + "data": ["views/website_sale_templates.xml"], + "assets": { + "web.assets_frontend": [ + "/website_decimal_quantity/static/src/js/variant_mixin.js", + "/website_decimal_quantity/static/src/js/website_sale.js", + "/website_decimal_quantity/static/src/js/website_sale_utils.js", + ] + }, + "license": "AGPL-3", + "installable": True, + "auto_install": False, + "application": False, +} diff --git a/website_decimal_quantity/controllers/__init__.py b/website_decimal_quantity/controllers/__init__.py new file mode 100644 index 0000000..0faffa3 --- /dev/null +++ b/website_decimal_quantity/controllers/__init__.py @@ -0,0 +1,22 @@ +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2023-TODAY Cybrosys Technologies(). +# Author: Vivek @ cybrosys,(odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU AFFERO +# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. +# +# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE +# (AGPL v3) along with this program. +# If not, see . +# +############################################################################# +from . import main +from . import website_sale_product_configurator diff --git a/website_decimal_quantity/controllers/main.py b/website_decimal_quantity/controllers/main.py new file mode 100644 index 0000000..ef0f625 --- /dev/null +++ b/website_decimal_quantity/controllers/main.py @@ -0,0 +1,193 @@ +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2023-TODAY Cybrosys Technologies(). +# Author: Vivek @ cybrosys,(odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU AFFERO +# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. +# +# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE +# (AGPL v3) along with this program. +# If not, see . +# +############################################################################# +from werkzeug.exceptions import NotFound + +from odoo import fields, http +from odoo.http import request +from odoo.tools.json import scriptsafe as json_scriptsafe + +from odoo.addons.payment import utils as payment_utils +from odoo.addons.website_sale.controllers.main import WebsiteSale + + +class WebsiteSaleDecimal(WebsiteSale): + """ + WebsiteSaleDecimal extends WebsiteSale class to update the methods: cart, cart_update, + cart_update_json and cart_quantity. + """ + + @http.route() + def cart(self, access_token=None, revive="", **post): + """ + Main cart management + abandoned cart revival + access_token: Abandoned cart SO access token + revive: Revival method when abandoned cart. Can be 'merge' or 'squash' + """ + order = request.website.sale_get_order() + if order and order.state != "draft": + request.session["sale_order_id"] = None + order = request.website.sale_get_order() + request.session["website_sale_cart_quantity"] = round( + sum(order.mapped("website_order_line.product_uom_qty")), 1 + ) + + values = {} + if access_token: + abandoned_order = request.env["sale.order"].sudo().search([("access_token", "=", access_token)], limit=1) + if not abandoned_order: + raise NotFound() + if abandoned_order.state != "draft": + values.update({"abandoned_proceed": True}) + elif revive == "squash" or (revive == "merge" and not request.session.get("sale_order_id")): + request.session["sale_order_id"] = abandoned_order.id + return request.redirect("/shop/cart") + elif revive == "merge": + abandoned_order.order_line.write({"order_id": request.session["sale_order_id"]}) + abandoned_order.action_cancel() + elif abandoned_order.id != request.session.get("sale_order_id"): + values.update({"access_token": abandoned_order.access_token}) + + values.update({"website_sale_order": order, "date": fields.Date.today(), "suggested_products": []}) + if order: + order.order_line.filtered(lambda l: not l.product_id.active).unlink() + values["suggested_products"] = order._cart_accessories() + values.update(self._get_express_shop_payment_values(order)) + + if post.get("type") == "popover": + # force no-cache so IE11 doesn't cache this XHR + return request.render("website_sale.cart_popover", values, headers={"Cache-Control": "no-cache"}) + + return request.render("website_sale.cart", values) + + @http.route() + def cart_update( + self, + product_id, + add_qty=1, + set_qty=0, + product_custom_attribute_values=None, + no_variant_attribute_values=None, + express=False, + **kwargs + ): + """This route is called when adding a product to cart (no options).""" + sale_order = request.website.sale_get_order(force_create=True) + if sale_order.state != "draft": + request.session["sale_order_id"] = None + sale_order = request.website.sale_get_order(force_create=True) + + if product_custom_attribute_values: + product_custom_attribute_values = json_scriptsafe.loads(product_custom_attribute_values) + + if no_variant_attribute_values: + no_variant_attribute_values = json_scriptsafe.loads(no_variant_attribute_values) + + sale_order._cart_update( + product_id=int(product_id), + add_qty=add_qty, + set_qty=set_qty, + product_custom_attribute_values=product_custom_attribute_values, + no_variant_attribute_values=no_variant_attribute_values, + **kwargs + ) + request.session["website_sale_cart_quantity"] = round( + sum(sale_order.mapped("website_order_line.product_uom_qty")), 1 + ) + + if express: + return request.redirect("/shop/checkout?express=1") + + return request.redirect("/shop/cart") + + @http.route() + def cart_update_json( + self, + product_id, + line_id=None, + add_qty=None, + set_qty=None, + display=True, + product_custom_attribute_values=None, + no_variant_attribute_values=None, + **kw + ): + """ + This route is called : + - When changing quantity from the cart. + - When adding a product from the wishlist. + - When adding a product to cart on the same page + (without redirection). + """ + order = request.website.sale_get_order(force_create=True) + if order.state != "draft": + request.website.sale_reset() + if kw.get("force_create"): + order = request.website.sale_get_order(force_create=True) + else: + return {} + + if product_custom_attribute_values: + product_custom_attribute_values = json_scriptsafe.loads(product_custom_attribute_values) + + if no_variant_attribute_values: + no_variant_attribute_values = json_scriptsafe.loads(no_variant_attribute_values) + + values = order._cart_update( + product_id=product_id, + line_id=line_id, + add_qty=add_qty, + set_qty=set_qty, + product_custom_attribute_values=product_custom_attribute_values, + no_variant_attribute_values=no_variant_attribute_values, + **kw + ) + request.session["website_sale_cart_quantity"] = round( + sum(order.mapped("website_order_line.product_uom_qty")), 1 + ) + + if not order.cart_quantity: + request.website.sale_reset() + return values + + values["cart_quantity"] = round(sum(order.mapped("website_order_line.product_uom_qty")), 1) + values["minor_amount"] = (payment_utils.to_minor_currency_units(order.amount_total, order.currency_id),) + values["amount"] = order.amount_total + + if not display: + return values + + values["website_sale.cart_lines"] = request.env["ir.ui.view"]._render_template( + "website_sale.cart_lines", + {"website_sale_order": order, "date": fields.Date.today(), "suggested_products": order._cart_accessories()}, + ) + values["website_sale.short_cart_summary"] = request.env["ir.ui.view"]._render_template( + "website_sale.short_cart_summary", {"website_sale_order": order} + ) + return values + + @http.route() + def cart_quantity(self): + """ + This method updates the cart quantity count in the session based on the order's website order lines. + """ + if "website_sale_cart_quantity" not in request.session: + return request.website.sale_get_order().mapped("website_order_line.product_uom_qty") + return request.session["website_sale_cart_quantity"] diff --git a/website_decimal_quantity/controllers/website_sale_product_configurator.py b/website_decimal_quantity/controllers/website_sale_product_configurator.py new file mode 100644 index 0000000..9a5d518 --- /dev/null +++ b/website_decimal_quantity/controllers/website_sale_product_configurator.py @@ -0,0 +1,90 @@ +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2023-TODAY Cybrosys Technologies(). +# Author: Vivek @ cybrosys,(odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU AFFERO +# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. +# +# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE +# (AGPL v3) along with this program. +# If not, see . +# +############################################################################# +import json + +from odoo import http +from odoo.http import request + +from odoo.addons.website_sale_product_configurator.controllers.main import WebsiteSale + + +class WebsiteSaleDecimal(WebsiteSale): + """ + WebsiteSaleDecimal extends WebsiteSale class to update the methods: cart_options_update_json. + """ + + @http.route() + def cart_options_update_json(self, product_and_options, goto_shop=None, lang=None, **kwargs): + """This route is called when submitting the optional product modal. + The product without parent is the main product, the other are + options. + Options need to be linked to their parents with a unique ID. + The main product is the first product in the list and the options + need to be right after their parent. + product_and_options { + 'product_id', + 'product_template_id', + 'quantity', + 'parent_unique_id', + 'unique_id', + 'product_custom_attribute_values', + 'no_variant_attribute_values' + } + """ + if lang: + request.website = request.website.with_context(lang=lang) + + order = request.website.sale_get_order(force_create=True) + if order.state != "draft": + request.session["sale_order_id"] = None + order = request.website.sale_get_order(force_create=True) + + product_and_options = json.loads(product_and_options) + if product_and_options: + # The main product is the first, optional products are the rest + main_product = product_and_options[0] + value = order._cart_update( + product_id=main_product["product_id"], + add_qty=main_product["quantity"], + product_custom_attribute_values=main_product["product_custom_attribute_values"], + no_variant_attribute_values=main_product["no_variant_attribute_values"], + **kwargs + ) + + if value["line_id"]: + # Link option with its parent iff line has been created. + option_parent = {main_product["unique_id"]: value["line_id"]} + for option in product_and_options[1:]: + parent_unique_id = option["parent_unique_id"] + option_value = order._cart_update( + product_id=option["product_id"], + set_qty=option["quantity"], + linked_line_id=option_parent[parent_unique_id], + product_custom_attribute_values=option["product_custom_attribute_values"], + no_variant_attribute_values=option["no_variant_attribute_values"], + **kwargs + ) + option_parent[option["unique_id"]] = option_value["line_id"] + request.session["website_sale_cart_quantity"] = round( + sum(order.mapped("website_order_line.product_uom_qty")), 1 + ) + + return str(round(sum(order.mapped("website_order_line.product_uom_qty")), 1)) diff --git a/website_decimal_quantity/doc/RELEASE_NOTES.md b/website_decimal_quantity/doc/RELEASE_NOTES.md new file mode 100644 index 0000000..2cbe542 --- /dev/null +++ b/website_decimal_quantity/doc/RELEASE_NOTES.md @@ -0,0 +1,9 @@ +## Module + +#### 15.02.2023 + +#### Version 16.0.1.0.0 + +#### ADD + +- Initial Commit for Website Decimal Quantity. diff --git a/website_decimal_quantity/models/__init__.py b/website_decimal_quantity/models/__init__.py new file mode 100644 index 0000000..09b1cbe --- /dev/null +++ b/website_decimal_quantity/models/__init__.py @@ -0,0 +1,21 @@ +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2023-TODAY Cybrosys Technologies(). +# Author: Vivek @ cybrosys,(odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU AFFERO +# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. +# +# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE +# (AGPL v3) along with this program. +# If not, see . +# +############################################################################# +from . import sale_order diff --git a/website_decimal_quantity/models/sale_order.py b/website_decimal_quantity/models/sale_order.py new file mode 100644 index 0000000..c3589f9 --- /dev/null +++ b/website_decimal_quantity/models/sale_order.py @@ -0,0 +1,106 @@ +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2023-TODAY Cybrosys Technologies(). +# Author: Vivek @ cybrosys,(odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU AFFERO +# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. +# +# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE +# (AGPL v3) along with this program. +# If not, see . +# +############################################################################# +from odoo import _, api, models +from odoo.exceptions import UserError +from odoo.http import request + + +class SaleOrder(models.Model): + _inherit = "sale.order" + """ + Inherit the 'sale.order' model to overwrite the _compute_cart_info and _cart_update functions. + """ + + @api.depends("order_line.product_uom_qty", "order_line.product_id") + def _compute_cart_info(self): + """ + Making cart_quantity integer is avoided in order + to represent it in decimal values + """ + for order in self: + order.cart_quantity = sum(order.mapped("website_order_line.product_uom_qty")) + order.only_services = all(line.product_id.type == "service" for line in order.website_order_line) + + def _cart_update(self, product_id, line_id=None, add_qty=0, set_qty=0, **kwargs): # noqa: C901 + """Add or set product quantity, add_qty can be negative. + + Making add_qty and set_qty integer are avoided in order + to represent them as decimal values. + """ + self.ensure_one() + if self.state != "draft": + request.session.pop("sale_order_id", None) + request.session.pop("website_sale_cart_quantity", None) + raise UserError(_("It is forbidden to modify a sales order which is not in draft status.")) + product = self.env["product.product"].browse(product_id).exists() + if not product or not product._is_add_to_cart_allowed(): + raise UserError(_("The given product does not exist therefore it cannot be added to cart.")) + if product.lst_price == 0 and product.website_id.prevent_zero_price_sale: + raise UserError(_("The given product does not have a price therefore it cannot be added to cart.")) + if line_id is not False: + order_line = self._cart_find_product_line(product_id, line_id, **kwargs)[:1] + else: + order_line = self.env["sale.order.line"] + try: + if add_qty: + pass + except ValueError: + add_qty = 1 + try: + if set_qty: + pass + except ValueError: + set_qty = 0 + quantity = 0 + if set_qty: + quantity = set_qty + elif add_qty is not None: + if order_line: + quantity = order_line.product_uom_qty + (add_qty or 0) + else: + quantity = add_qty or 0 + if quantity > 0: + quantity, warning = self._verify_updated_quantity(order_line, product_id, quantity, **kwargs) + else: + # If the line will be removed anyway, there is no need to verify + # the requested quantity update. + warning = "" + if order_line and quantity <= 0: + # Remove zero or negative lines + order_line.unlink() + order_line = self.env["sale.order.line"] + elif order_line: + # Update existing line + update_values = self._prepare_order_line_update_values(order_line, quantity, **kwargs) + if update_values: + self._update_cart_line_values(order_line, update_values) + elif quantity >= 0: + # Create new line + order_line_values = self._prepare_order_line_values(product_id, quantity, **kwargs) + order_line = self.env["sale.order.line"].sudo().create(order_line_values) + return { + "line_id": order_line.id, + "quantity": quantity, + "option_ids": list( + set(order_line.option_line_ids.filtered(lambda l: l.order_id == order_line.order_id).ids) + ), + "warning": warning, + } diff --git a/website_decimal_quantity/readme/CONTRIBUTORS.rst b/website_decimal_quantity/readme/CONTRIBUTORS.rst new file mode 100644 index 0000000..243ea26 --- /dev/null +++ b/website_decimal_quantity/readme/CONTRIBUTORS.rst @@ -0,0 +1,2 @@ +- Cybrosys Techno Solutions +- BAKEUP \ No newline at end of file diff --git a/website_decimal_quantity/readme/DESCRIPTION.rst b/website_decimal_quantity/readme/DESCRIPTION.rst new file mode 100644 index 0000000..9e41803 --- /dev/null +++ b/website_decimal_quantity/readme/DESCRIPTION.rst @@ -0,0 +1,3 @@ +The app allows to select quantity in decimal for products in Website/Shop", + "description": """ + The app allows to select quantity in decimal for products in Website/Shop \ No newline at end of file diff --git a/website_decimal_quantity/readme/HISTORY.rst b/website_decimal_quantity/readme/HISTORY.rst new file mode 100644 index 0000000..e8d59fb --- /dev/null +++ b/website_decimal_quantity/readme/HISTORY.rst @@ -0,0 +1 @@ +- 16.0.1.0.0: Initial version \ No newline at end of file diff --git a/website_decimal_quantity/static/description/assets/icons/check.png b/website_decimal_quantity/static/description/assets/icons/check.png new file mode 100644 index 0000000..c8e85f5 Binary files /dev/null and b/website_decimal_quantity/static/description/assets/icons/check.png differ diff --git a/website_decimal_quantity/static/description/assets/icons/chevron.png b/website_decimal_quantity/static/description/assets/icons/chevron.png new file mode 100644 index 0000000..2089293 Binary files /dev/null and b/website_decimal_quantity/static/description/assets/icons/chevron.png differ diff --git a/website_decimal_quantity/static/description/assets/icons/cogs.png b/website_decimal_quantity/static/description/assets/icons/cogs.png new file mode 100644 index 0000000..95d0bad Binary files /dev/null and b/website_decimal_quantity/static/description/assets/icons/cogs.png differ diff --git a/website_decimal_quantity/static/description/assets/icons/consultation.png b/website_decimal_quantity/static/description/assets/icons/consultation.png new file mode 100644 index 0000000..8319d4b Binary files /dev/null and b/website_decimal_quantity/static/description/assets/icons/consultation.png differ diff --git a/website_decimal_quantity/static/description/assets/icons/ecom-black.png b/website_decimal_quantity/static/description/assets/icons/ecom-black.png new file mode 100644 index 0000000..a9385ff Binary files /dev/null and b/website_decimal_quantity/static/description/assets/icons/ecom-black.png differ diff --git a/website_decimal_quantity/static/description/assets/icons/education-black.png b/website_decimal_quantity/static/description/assets/icons/education-black.png new file mode 100644 index 0000000..3eb09b2 Binary files /dev/null and b/website_decimal_quantity/static/description/assets/icons/education-black.png differ diff --git a/website_decimal_quantity/static/description/assets/icons/hotel-black.png b/website_decimal_quantity/static/description/assets/icons/hotel-black.png new file mode 100644 index 0000000..130f613 Binary files /dev/null and b/website_decimal_quantity/static/description/assets/icons/hotel-black.png differ diff --git a/website_decimal_quantity/static/description/assets/icons/license.png b/website_decimal_quantity/static/description/assets/icons/license.png new file mode 100644 index 0000000..a586979 Binary files /dev/null and b/website_decimal_quantity/static/description/assets/icons/license.png differ diff --git a/website_decimal_quantity/static/description/assets/icons/lifebuoy.png b/website_decimal_quantity/static/description/assets/icons/lifebuoy.png new file mode 100644 index 0000000..658d56c Binary files /dev/null and b/website_decimal_quantity/static/description/assets/icons/lifebuoy.png differ diff --git a/website_decimal_quantity/static/description/assets/icons/manufacturing-black.png b/website_decimal_quantity/static/description/assets/icons/manufacturing-black.png new file mode 100644 index 0000000..697eb0e Binary files /dev/null and b/website_decimal_quantity/static/description/assets/icons/manufacturing-black.png differ diff --git a/website_decimal_quantity/static/description/assets/icons/pos-black.png b/website_decimal_quantity/static/description/assets/icons/pos-black.png new file mode 100644 index 0000000..97c0f90 Binary files /dev/null and b/website_decimal_quantity/static/description/assets/icons/pos-black.png differ diff --git a/website_decimal_quantity/static/description/assets/icons/puzzle.png b/website_decimal_quantity/static/description/assets/icons/puzzle.png new file mode 100644 index 0000000..65cf854 Binary files /dev/null and b/website_decimal_quantity/static/description/assets/icons/puzzle.png differ diff --git a/website_decimal_quantity/static/description/assets/icons/restaurant-black.png b/website_decimal_quantity/static/description/assets/icons/restaurant-black.png new file mode 100644 index 0000000..4a35eb9 Binary files /dev/null and b/website_decimal_quantity/static/description/assets/icons/restaurant-black.png differ diff --git a/website_decimal_quantity/static/description/assets/icons/service-black.png b/website_decimal_quantity/static/description/assets/icons/service-black.png new file mode 100644 index 0000000..301ab51 Binary files /dev/null and b/website_decimal_quantity/static/description/assets/icons/service-black.png differ diff --git a/website_decimal_quantity/static/description/assets/icons/trading-black.png b/website_decimal_quantity/static/description/assets/icons/trading-black.png new file mode 100644 index 0000000..9398ba2 Binary files /dev/null and b/website_decimal_quantity/static/description/assets/icons/trading-black.png differ diff --git a/website_decimal_quantity/static/description/assets/icons/training.png b/website_decimal_quantity/static/description/assets/icons/training.png new file mode 100644 index 0000000..884ca02 Binary files /dev/null and b/website_decimal_quantity/static/description/assets/icons/training.png differ diff --git a/website_decimal_quantity/static/description/assets/icons/update.png b/website_decimal_quantity/static/description/assets/icons/update.png new file mode 100644 index 0000000..ecbc5a0 Binary files /dev/null and b/website_decimal_quantity/static/description/assets/icons/update.png differ diff --git a/website_decimal_quantity/static/description/assets/icons/user.png b/website_decimal_quantity/static/description/assets/icons/user.png new file mode 100644 index 0000000..6ffb23d Binary files /dev/null and b/website_decimal_quantity/static/description/assets/icons/user.png differ diff --git a/website_decimal_quantity/static/description/assets/icons/wrench.png b/website_decimal_quantity/static/description/assets/icons/wrench.png new file mode 100644 index 0000000..6c04dea Binary files /dev/null and b/website_decimal_quantity/static/description/assets/icons/wrench.png differ diff --git a/website_decimal_quantity/static/description/assets/misc/categories.png b/website_decimal_quantity/static/description/assets/misc/categories.png new file mode 100644 index 0000000..bedf1e0 Binary files /dev/null and b/website_decimal_quantity/static/description/assets/misc/categories.png differ diff --git a/website_decimal_quantity/static/description/assets/misc/check-box.png b/website_decimal_quantity/static/description/assets/misc/check-box.png new file mode 100644 index 0000000..42caf24 Binary files /dev/null and b/website_decimal_quantity/static/description/assets/misc/check-box.png differ diff --git a/website_decimal_quantity/static/description/assets/misc/compass.png b/website_decimal_quantity/static/description/assets/misc/compass.png new file mode 100644 index 0000000..d5fed8f Binary files /dev/null and b/website_decimal_quantity/static/description/assets/misc/compass.png differ diff --git a/website_decimal_quantity/static/description/assets/misc/corporate.png b/website_decimal_quantity/static/description/assets/misc/corporate.png new file mode 100644 index 0000000..2eb13ed Binary files /dev/null and b/website_decimal_quantity/static/description/assets/misc/corporate.png differ diff --git a/website_decimal_quantity/static/description/assets/misc/customer-support.png b/website_decimal_quantity/static/description/assets/misc/customer-support.png new file mode 100644 index 0000000..79efc72 Binary files /dev/null and b/website_decimal_quantity/static/description/assets/misc/customer-support.png differ diff --git a/website_decimal_quantity/static/description/assets/misc/cybrosys-logo.png b/website_decimal_quantity/static/description/assets/misc/cybrosys-logo.png new file mode 100644 index 0000000..cc3cc0c Binary files /dev/null and b/website_decimal_quantity/static/description/assets/misc/cybrosys-logo.png differ diff --git a/website_decimal_quantity/static/description/assets/misc/features.png b/website_decimal_quantity/static/description/assets/misc/features.png new file mode 100644 index 0000000..b41769f Binary files /dev/null and b/website_decimal_quantity/static/description/assets/misc/features.png differ diff --git a/website_decimal_quantity/static/description/assets/misc/logo.png b/website_decimal_quantity/static/description/assets/misc/logo.png new file mode 100644 index 0000000..478462d Binary files /dev/null and b/website_decimal_quantity/static/description/assets/misc/logo.png differ diff --git a/website_decimal_quantity/static/description/assets/misc/pictures.png b/website_decimal_quantity/static/description/assets/misc/pictures.png new file mode 100644 index 0000000..56d255f Binary files /dev/null and b/website_decimal_quantity/static/description/assets/misc/pictures.png differ diff --git a/website_decimal_quantity/static/description/assets/misc/pie-chart.png b/website_decimal_quantity/static/description/assets/misc/pie-chart.png new file mode 100644 index 0000000..426e052 Binary files /dev/null and b/website_decimal_quantity/static/description/assets/misc/pie-chart.png differ diff --git a/website_decimal_quantity/static/description/assets/misc/right-arrow.png b/website_decimal_quantity/static/description/assets/misc/right-arrow.png new file mode 100644 index 0000000..730984a Binary files /dev/null and b/website_decimal_quantity/static/description/assets/misc/right-arrow.png differ diff --git a/website_decimal_quantity/static/description/assets/misc/star.png b/website_decimal_quantity/static/description/assets/misc/star.png new file mode 100644 index 0000000..2eb9ab2 Binary files /dev/null and b/website_decimal_quantity/static/description/assets/misc/star.png differ diff --git a/website_decimal_quantity/static/description/assets/misc/support.png b/website_decimal_quantity/static/description/assets/misc/support.png new file mode 100644 index 0000000..4f18b8b Binary files /dev/null and b/website_decimal_quantity/static/description/assets/misc/support.png differ diff --git a/website_decimal_quantity/static/description/assets/misc/whatsapp.png b/website_decimal_quantity/static/description/assets/misc/whatsapp.png new file mode 100644 index 0000000..d513a53 Binary files /dev/null and b/website_decimal_quantity/static/description/assets/misc/whatsapp.png differ diff --git a/website_decimal_quantity/static/description/assets/modules/1.png b/website_decimal_quantity/static/description/assets/modules/1.png new file mode 100644 index 0000000..359d3e4 Binary files /dev/null and b/website_decimal_quantity/static/description/assets/modules/1.png differ diff --git a/website_decimal_quantity/static/description/assets/modules/2.png b/website_decimal_quantity/static/description/assets/modules/2.png new file mode 100644 index 0000000..5c56f0b Binary files /dev/null and b/website_decimal_quantity/static/description/assets/modules/2.png differ diff --git a/website_decimal_quantity/static/description/assets/modules/3.png b/website_decimal_quantity/static/description/assets/modules/3.png new file mode 100644 index 0000000..c1f3035 Binary files /dev/null and b/website_decimal_quantity/static/description/assets/modules/3.png differ diff --git a/website_decimal_quantity/static/description/assets/modules/4.png b/website_decimal_quantity/static/description/assets/modules/4.png new file mode 100644 index 0000000..33372bd Binary files /dev/null and b/website_decimal_quantity/static/description/assets/modules/4.png differ diff --git a/website_decimal_quantity/static/description/assets/modules/5.gif b/website_decimal_quantity/static/description/assets/modules/5.gif new file mode 100644 index 0000000..d0f36b0 Binary files /dev/null and b/website_decimal_quantity/static/description/assets/modules/5.gif differ diff --git a/website_decimal_quantity/static/description/assets/modules/6.png b/website_decimal_quantity/static/description/assets/modules/6.png new file mode 100644 index 0000000..29d072e Binary files /dev/null and b/website_decimal_quantity/static/description/assets/modules/6.png differ diff --git a/website_decimal_quantity/static/description/assets/screenshots/1.png b/website_decimal_quantity/static/description/assets/screenshots/1.png new file mode 100644 index 0000000..286afcb Binary files /dev/null and b/website_decimal_quantity/static/description/assets/screenshots/1.png differ diff --git a/website_decimal_quantity/static/description/assets/screenshots/2.png b/website_decimal_quantity/static/description/assets/screenshots/2.png new file mode 100644 index 0000000..328244e Binary files /dev/null and b/website_decimal_quantity/static/description/assets/screenshots/2.png differ diff --git a/website_decimal_quantity/static/description/assets/screenshots/3.png b/website_decimal_quantity/static/description/assets/screenshots/3.png new file mode 100644 index 0000000..302c8fc Binary files /dev/null and b/website_decimal_quantity/static/description/assets/screenshots/3.png differ diff --git a/website_decimal_quantity/static/description/assets/screenshots/hero.gif b/website_decimal_quantity/static/description/assets/screenshots/hero.gif new file mode 100644 index 0000000..6409f7a Binary files /dev/null and b/website_decimal_quantity/static/description/assets/screenshots/hero.gif differ diff --git a/website_decimal_quantity/static/description/banner.png b/website_decimal_quantity/static/description/banner.png new file mode 100644 index 0000000..29e8179 Binary files /dev/null and b/website_decimal_quantity/static/description/banner.png differ diff --git a/website_decimal_quantity/static/description/icon.png b/website_decimal_quantity/static/description/icon.png new file mode 100644 index 0000000..8191d4f Binary files /dev/null and b/website_decimal_quantity/static/description/icon.png differ diff --git a/website_decimal_quantity/static/description/index.html b/website_decimal_quantity/static/description/index.html new file mode 100644 index 0000000..d9c68f3 --- /dev/null +++ b/website_decimal_quantity/static/description/index.html @@ -0,0 +1,612 @@ +
+ +
+ +
+
+ Community +
+
+ Enterprise +
+ +
+
+ + + +

Website + Decimal Quantity

+

Select Decimal Product Quantity + from Website

+ + + +
+ + +
+
+ +
+

Explore This + Module

+
+ + + + +
+
+ +
+

Overview +

+
+
+
+ This module allows users to choose products from the website shop in decimal quantities. This can be helpful + for users who need to select products in decimal quantities rather than multiples of one. +
+
+ + + +
+
+ +
+

+ Configuration +

+
+
+
+ No additional configuration required. +
+
+ + + + +
+
+ +
+

+ Features +

+
+
+
+
+ + Decimal Product Quantity +

+ Allows users to select product in decimal quantities from product and cart page in Website/Shop.

+
+
+ + Simultaneous Price Calculation +

+ Simultaneous price calculation in the cart according to the selected decimal quantities.

+
+ +
+
+ + + +
+
+ +
+

Screenshots +

+
+
+
+ +
+

Decimal Product + Quantity in Product Page

+

Select product + quantities in decimal values from Product Page.

+ +
+ +
+

Decimal Product + Quantity in Cart Page

+

Select product + quantities in decimal values from Cart Page.

+ +
+ +
+

Simultaneous price + calculation in cart

+

Price is calculated in + the cart according to the decimal product values.

+ +
+ +
+
+ + + +
+
+ +
+

+ Related + Products +

+
+
+
+ +
+
+ + + + +
+
+ +
+

Our Services +

+
+ +
+
+
+
+ +
+
+ Odoo + Customization
+
+ +
+
+ +
+
+ Odoo + Implementation
+
+ +
+
+ +
+
+ Odoo + Support
+
+ + +
+
+ +
+
+ Hire + Odoo + Developer
+
+ +
+
+ +
+
+ Odoo + Integration
+
+ +
+
+ +
+
+ Odoo + Migration
+
+ + +
+
+ +
+
+ Odoo + Consultancy
+
+ +
+
+ +
+
+ Odoo + Implementation
+
+ +
+
+ +
+
+ Odoo + Licensing Consultancy
+
+
+ +
+ + + + + +
+
+ +
+

Our + Industries +

+
+ +
+
+
+
+ +
+ Trading +
+

+ Easily procure + and + sell your products

+
+
+ +
+
+ +
+ POS +
+

+ Easy + configuration + and convivial experience

+
+
+ +
+
+ +
+ Education +
+

+ A platform for + educational management

+
+
+ +
+
+ +
+ Manufacturing +
+

+ Plan, track and + schedule your operations

+
+
+ +
+
+ +
+ E-commerce & Website +
+

+ Mobile + friendly, + awe-inspiring product pages

+
+
+ +
+
+ +
+ Service Management +
+

+ Keep track of + services and invoice

+
+
+ +
+
+ +
+ Restaurant +
+

+ Run your bar or + restaurant methodically

+
+
+ +
+
+ +
+ Hotel Management +
+

+ An + all-inclusive + hotel management application

+
+
+
+
+ + + + +
+
+ +
+

Support +

+
+
+
+
+
+
+ +
+
+

Need Help?

+

Got questions or need help? Get in touch.

+ +

+ odoo@cybrosys.com

+
+
+
+
+
+
+
+ +
+
+

WhatsApp

+

Say hi to us on WhatsApp!

+ +

+91 86068 + 27707

+
+
+
+
+
+
+
+ +
+
+
+ \ No newline at end of file diff --git a/website_decimal_quantity/static/src/js/variant_mixin.js b/website_decimal_quantity/static/src/js/variant_mixin.js new file mode 100644 index 0000000..4eea056 --- /dev/null +++ b/website_decimal_quantity/static/src/js/variant_mixin.js @@ -0,0 +1,28 @@ +odoo.define("website_decimal_qty.VariantMixin", function (require) { + "use strict"; + + var VariantMixin = require("sale.VariantMixin"); + + /** + * A custom implementation of the onClickAddCartJSON function in the + * sale.VariantMixin module. It allows for decimal quantities to be added to the cart + * by updating the input value with increments of 0.1. + */ + + VariantMixin.onClickAddCartJSON = function (ev) { + ev.preventDefault(); + var $link = $(ev.currentTarget); + var $input = $link.closest(".input-group").find("input"); + var min = parseFloat($input.data("min") || 0); + var max = parseFloat($input.data("max") || Infinity); + var previousQty = parseFloat($input.val() || 0, 10); + var quantity = ($link.has(".fa-minus").length ? -0.1 : 0.1) + previousQty; + var newQt = quantity > min ? (quantity < max ? quantity : max) : min; + if (newQt !== previousQty) { + var newQty = newQt.toFixed(1); + $input.val(newQty).trigger("change"); + } + newQty = newQt.toFixed(1); + return false; + }; +}); diff --git a/website_decimal_quantity/static/src/js/website_sale.js b/website_decimal_quantity/static/src/js/website_sale.js new file mode 100644 index 0000000..f68b96f --- /dev/null +++ b/website_decimal_quantity/static/src/js/website_sale.js @@ -0,0 +1,86 @@ +odoo.define("website_decimal_qty.website_sale", function (require) { + "use strict"; + + var publicWidget = require("web.public.widget"); + var wSaleUtils = require("website_sale.utils"); + require("website_sale.website_sale"); + + /** + * This module extends the website_sale module to support decimal quantity input for adding products to the cart. + * It overrides the onClickAddCartJSON function from sale.VariantMixin to add support for decimal quantity input, + * and extends the WebsiteSale widget to handle updating cart quantities when a decimal quantity is entered. + */ + + publicWidget.registry.WebsiteSale.include({ + _changeCartQuantity: function ($input, value, $dom_optional, line_id, productIDs) { + _.each($dom_optional, function (elem) { + $(elem).find(".js_quantity").text(value); + productIDs.push($(elem).find("span[data-product-id]").data("product-id")); + }); + $input.data("update_change", true); + + this._rpc({ + route: "/shop/cart/update_json", + params: { + line_id: line_id, + product_id: parseInt($input.data("product-id"), 10), + set_qty: value, + }, + }).then(function (data) { + $input.data("update_change", false); + var check_value = parseFloat($input.val()); + + if (isNaN(check_value)) { + check_value = 1; + } + if (value !== check_value) { + $input.trigger("change"); + return; + } + if (!data.cart_quantity) { + return (window.location = "/shop/cart"); + } + wSaleUtils.updateCartNavBar(data); + $input.val(data.quantity); + + $(".js_quantity[data-line-id=" + line_id + "]") + .val(data.quantity) + .text(data.quantity); + + if (data.warning) { + var cart_alert = $(".oe_cart").parent().find("#data_warning"); + if (cart_alert.length === 0) { + $(".oe_cart").prepend( + '" + ); + } else { + cart_alert.html( + ' ' + + data.warning + ); + } + $input.val(data.quantity); + } + }); + }, + + _onChangeCartQuantity: function (ev) { + var $input = $(ev.currentTarget); + if ($input.data("update_change")) { + return; + } + var value = parseFloat($input.val() || 0, 10); + if (isNaN(value)) { + value = 1; + } + var $dom = $input.closest("tr"); + var $dom_optional = $dom.nextUntil(":not(.optional_product.info)"); + var line_id = parseInt($input.data("line-id"), 10); + var productIDs = [parseInt($input.data("product-id"), 10)]; + this._changeCartQuantity($input, value, $dom_optional, line_id, productIDs); + }, + }); +}); diff --git a/website_decimal_quantity/static/src/js/website_sale_utils.js b/website_decimal_quantity/static/src/js/website_sale_utils.js new file mode 100644 index 0000000..2c0f010 --- /dev/null +++ b/website_decimal_quantity/static/src/js/website_sale_utils.js @@ -0,0 +1,31 @@ +odoo.define("website_decimal_quantity.utils", function (require) { + "use strict"; + + var utils = require("website_sale.utils"); + + /** + * This module overrides the updateCartNavBar function of the website_sale.utils module to provide + * support for decimal quantities in the cart. + * It replaces the cart quantity text with an animated icon and updates the cart summary and lines with the new data. + */ + + utils.updateCartNavBar = function (data) { + $(".my_cart_quantity") + .parents("li.o_wsale_my_cart") + .removeClass("d-none") + .end() + .addClass("o_mycart_zoom_animation") + .delay(300) + .queue(function () { + $(this) + .toggleClass("fa fa-warning", !data.cart_quantity) + .attr("title", data.warning) + .text(data.cart_quantity || "") + .removeClass("o_mycart_zoom_animation") + .dequeue(); + }); + + $(".js_cart_lines").first().before(data["website_sale.cart_lines"]).end().remove(); + $(".js_cart_summary").replaceWith(data["website_sale.short_cart_summary"]); + }; +}); diff --git a/website_decimal_quantity/views/website_sale_templates.xml b/website_decimal_quantity/views/website_sale_templates.xml new file mode 100644 index 0000000..3d5e9e7 --- /dev/null +++ b/website_decimal_quantity/views/website_sale_templates.xml @@ -0,0 +1,31 @@ + + + + + + + +