diff --git a/call_for_price_website/README.rst b/call_for_price_website/README.rst index e72e7ba9e..a13711ee4 100644 --- a/call_for_price_website/README.rst +++ b/call_for_price_website/README.rst @@ -3,7 +3,7 @@ :alt: License: AGPL-3 WEBSITE CALL FOR PRICE -==================== +====================== This module helps hide specific products prices from the shop and using 'Call for Price' button customer can sent their details, the user will follow up the details and get the product price. Configuration @@ -16,7 +16,7 @@ Company Credits ------- -Developer: Raneesha M K @cybrosys, Contact: odoo@cybrosys.com +Developers: Raneesha M K @cybrosys, Muhsina V @cybrosys, Contact: odoo@cybrosys.com Contacts -------- @@ -39,4 +39,4 @@ For support and more information, please visit `Our Website `__ \ No newline at end of file +HTML Description: ``__ diff --git a/call_for_price_website/__manifest__.py b/call_for_price_website/__manifest__.py index 9dcee98b8..3d3ba0ed3 100644 --- a/call_for_price_website/__manifest__.py +++ b/call_for_price_website/__manifest__.py @@ -21,15 +21,15 @@ ############################################################################### { 'name': 'Website Call For Price', - 'version': '16.0.1.0.0', - 'category': 'Website/Website', + 'version': '16.0.1.0.1', + 'category': 'Website', 'author': 'Cybrosys Techno Solutions', 'company': 'Cybrosys Techno Solutions', 'maintainer': 'Cybrosys Techno Solutions', 'images': ['static/description/banner.png'], 'website': 'https://www.cybrosys.com', 'depends': ['base', 'website_sale', 'website_sale_wishlist', - 'website_sale_comparison'], + 'website_sale_comparison', 'stock'], 'summary': """Helps to hide price of specified product from shop""", 'description': "Hide price and add to cart item button of All page stores" "and user must ask for a call for price", @@ -38,10 +38,13 @@ 'views/wishlist_hide_price_template.xml', 'views/compare_hide_price_template.xml', 'views/call_for_price_views.xml', - 'views/product_template_views.xml'], + 'views/product_product_views.xml', + ], 'assets': { 'web.assets_frontend': [ - '/call_for_price_website/static/src/js/create_call_form.js'] + '/call_for_price_website/static/src/js/create_call_form.js', + '/call_for_price_website/static/src/js/variant_mixin.js' + ] }, 'license': 'AGPL-3', 'installable': True, diff --git a/call_for_price_website/doc/RELEASE_NOTES.md b/call_for_price_website/doc/RELEASE_NOTES.md index 851efaf7d..94bee893c 100644 --- a/call_for_price_website/doc/RELEASE_NOTES.md +++ b/call_for_price_website/doc/RELEASE_NOTES.md @@ -5,7 +5,7 @@ #### ADD Initial Commit for Website Call For Price - - - - +#### 13.09.2023 +#### Version 16.0.1.0.1 +#### UPDT +- Updated the "Call for Price" option for the product variant; originally, it was at the product level. diff --git a/call_for_price_website/models/__init__.py b/call_for_price_website/models/__init__.py index ca776bd5b..bd391ba5b 100644 --- a/call_for_price_website/models/__init__.py +++ b/call_for_price_website/models/__init__.py @@ -20,4 +20,5 @@ # ############################################################################### -from . import call_price, product_template +from . import call_price +from . import product_product diff --git a/call_for_price_website/models/product_product.py b/call_for_price_website/models/product_product.py new file mode 100644 index 000000000..e1119cfea --- /dev/null +++ b/call_for_price_website/models/product_product.py @@ -0,0 +1,57 @@ +# -*- coding: utf-8 -*- +############################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2023-TODAY Cybrosys Technologies() +# Author: Raneesha M K (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 fields, models + + +class ProductTemplate(models.Model): + """Inheriting product template model for adding the field price_call into + the combination_info""" + _inherit = 'product.template' + + def _get_combination_info(self, combination=False, product_id=False, + add_qty=1, pricelist=False, + parent_combination=False, + only_template=False): + # Call the parent method to get the initial combination_info + combination_info = super(ProductTemplate, + self)._get_combination_info( + combination=combination, product_id=product_id, + add_qty=add_qty, pricelist=pricelist, + parent_combination=parent_combination, + only_template=only_template) + + if combination_info.get('product_id'): + product = self.env['product.product'].browse( + combination_info['product_id']) + combination_info['price_call'] = product.price_call + return combination_info + + +class ProductProduct(models.Model): + """Inheriting product variants model for adding a field that will hide + price from website""" + _inherit = 'product.product' + + price_call = fields.Boolean(string="Call for Price", + help="This will hide the price and cart button" + "from shop and customer can request by " + "calling for price") diff --git a/call_for_price_website/models/product_template.py b/call_for_price_website/models/product_template.py deleted file mode 100644 index e271a3761..000000000 --- a/call_for_price_website/models/product_template.py +++ /dev/null @@ -1,32 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################### -# -# Cybrosys Technologies Pvt. Ltd. -# -# Copyright (C) 2023-TODAY Cybrosys Technologies() -# Author: Raneesha M K (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 fields, models - - -class ProductTemplate(models.Model): - """Inheriting product variants model for adding a field - that will hide price from website""" - _inherit = 'product.template' - - price_call = fields.Boolean(string="Call for Price", - help="This will hide the price and cart button from shop " - "and customer can request by calling for price") diff --git a/call_for_price_website/static/description/assets/screenshots/1.png b/call_for_price_website/static/description/assets/screenshots/1.png new file mode 100644 index 000000000..1c993d922 Binary files /dev/null and b/call_for_price_website/static/description/assets/screenshots/1.png differ diff --git a/call_for_price_website/static/description/assets/screenshots/2.png b/call_for_price_website/static/description/assets/screenshots/2.png new file mode 100644 index 000000000..595570355 Binary files /dev/null and b/call_for_price_website/static/description/assets/screenshots/2.png differ diff --git a/call_for_price_website/static/description/assets/screenshots/3.png b/call_for_price_website/static/description/assets/screenshots/3.png new file mode 100644 index 000000000..d85537dd0 Binary files /dev/null and b/call_for_price_website/static/description/assets/screenshots/3.png differ diff --git a/call_for_price_website/static/description/assets/screenshots/4.png b/call_for_price_website/static/description/assets/screenshots/4.png new file mode 100644 index 000000000..89a2ac2e8 Binary files /dev/null and b/call_for_price_website/static/description/assets/screenshots/4.png differ diff --git a/call_for_price_website/static/description/assets/screenshots/5.png b/call_for_price_website/static/description/assets/screenshots/5.png new file mode 100644 index 000000000..2432da619 Binary files /dev/null and b/call_for_price_website/static/description/assets/screenshots/5.png differ diff --git a/call_for_price_website/static/description/assets/screenshots/6.png b/call_for_price_website/static/description/assets/screenshots/6.png new file mode 100644 index 000000000..b12c63c8d Binary files /dev/null and b/call_for_price_website/static/description/assets/screenshots/6.png differ diff --git a/call_for_price_website/static/description/assets/screenshots/7.png b/call_for_price_website/static/description/assets/screenshots/7.png new file mode 100644 index 000000000..3e21098a4 Binary files /dev/null and b/call_for_price_website/static/description/assets/screenshots/7.png differ diff --git a/call_for_price_website/static/description/assets/screenshots/8.png b/call_for_price_website/static/description/assets/screenshots/8.png new file mode 100644 index 000000000..cc0ecbdc7 Binary files /dev/null and b/call_for_price_website/static/description/assets/screenshots/8.png differ diff --git a/call_for_price_website/static/description/assets/screenshots/Screenshot1.png b/call_for_price_website/static/description/assets/screenshots/Screenshot1.png deleted file mode 100644 index 6f75249b6..000000000 Binary files a/call_for_price_website/static/description/assets/screenshots/Screenshot1.png and /dev/null differ diff --git a/call_for_price_website/static/description/assets/screenshots/Screenshot2.png b/call_for_price_website/static/description/assets/screenshots/Screenshot2.png deleted file mode 100644 index 3685eb05a..000000000 Binary files a/call_for_price_website/static/description/assets/screenshots/Screenshot2.png and /dev/null differ diff --git a/call_for_price_website/static/description/assets/screenshots/Screenshot3.png b/call_for_price_website/static/description/assets/screenshots/Screenshot3.png deleted file mode 100644 index 9f16188b8..000000000 Binary files a/call_for_price_website/static/description/assets/screenshots/Screenshot3.png and /dev/null differ diff --git a/call_for_price_website/static/description/assets/screenshots/Screenshot4.png b/call_for_price_website/static/description/assets/screenshots/Screenshot4.png deleted file mode 100644 index f4d20c03f..000000000 Binary files a/call_for_price_website/static/description/assets/screenshots/Screenshot4.png and /dev/null differ diff --git a/call_for_price_website/static/description/assets/screenshots/Screenshot5.png b/call_for_price_website/static/description/assets/screenshots/Screenshot5.png deleted file mode 100644 index cdf9abfa4..000000000 Binary files a/call_for_price_website/static/description/assets/screenshots/Screenshot5.png and /dev/null differ diff --git a/call_for_price_website/static/description/assets/screenshots/Screenshot6.png b/call_for_price_website/static/description/assets/screenshots/Screenshot6.png deleted file mode 100644 index 668803191..000000000 Binary files a/call_for_price_website/static/description/assets/screenshots/Screenshot6.png and /dev/null differ diff --git a/call_for_price_website/static/description/assets/screenshots/Screenshot7.png b/call_for_price_website/static/description/assets/screenshots/Screenshot7.png deleted file mode 100644 index c212dd592..000000000 Binary files a/call_for_price_website/static/description/assets/screenshots/Screenshot7.png and /dev/null differ diff --git a/call_for_price_website/static/description/assets/screenshots/Screenshot8.png b/call_for_price_website/static/description/assets/screenshots/Screenshot8.png deleted file mode 100644 index a6484ca8c..000000000 Binary files a/call_for_price_website/static/description/assets/screenshots/Screenshot8.png and /dev/null differ diff --git a/call_for_price_website/static/description/assets/screenshots/hero.gif b/call_for_price_website/static/description/assets/screenshots/hero.gif index 3f5a934ab..4170d7df3 100644 Binary files a/call_for_price_website/static/description/assets/screenshots/hero.gif and b/call_for_price_website/static/description/assets/screenshots/hero.gif differ diff --git a/call_for_price_website/static/description/index.html b/call_for_price_website/static/description/index.html index a2c737fe3..aadbb3998 100644 --- a/call_for_price_website/static/description/index.html +++ b/call_for_price_website/static/description/index.html @@ -110,11 +110,13 @@
- In some cases, we have to hide the price of a product. These items might - be free, out of stock, or available for - any other reason. This module allows you to hide the price and add to - cart button for specific products; the - call for price option will send a price request to the merchant. + In certain situations, it becomes necessary to conceal the price of a + product or one of its variants. These instances may arise due to + various reasons such as customization, availability issues, or when + the product is offered for free. This module facilitates the hiding of + prices and the addition of a "Add to Cart" button for designated + products. The "Call for Price" option enables customers to send a + price inquiry to the merchant.
@@ -178,24 +180,25 @@ Enable Call for Price from the Product Sales tab

- Go to Products -> Sales -> + Go to Product variants -> Sales -> Enable Call for Price. After enabling this, the price and add to cart button will hide from the website.

- +

Hide product price from list of products

- +

Wishlist page

- Hide the price and add to cart button from wishlist page.

- + Conceal the price and "Add to Cart" button on the wishlist page + for either the product or its specific variant.

+
@@ -204,7 +207,7 @@

If the user needs to compare the products, then they need to request the price.

- +
@@ -214,7 +217,7 @@ Hides the price and add to cart button from product item and adds button for price request, on clicking a popup will open.

- +
@@ -224,16 +227,16 @@ User need to enter these details inorder to get the price of the product. The request will send to merchant by clicking send button.

- +

- Request Sended

+ Request Sent

After sending the request a success message will show there, and merchant can access the request from backend.

- +
@@ -242,7 +245,7 @@

Initially, a draft request is created; after merchant verification, the sales team contacts the customer.

- +
diff --git a/call_for_price_website/static/src/js/create_call_form.js b/call_for_price_website/static/src/js/create_call_form.js index c7fbf648a..eb660cb82 100644 --- a/call_for_price_website/static/src/js/create_call_form.js +++ b/call_for_price_website/static/src/js/create_call_form.js @@ -1,26 +1,122 @@ /** - * This file is used to give a success alert after requesting a call for price. -*/ - -odoo.define('call_for_price_website.create', function (require) { -"use strict"; + * This file is used to give a success alert after requesting a call for price. + */ +odoo.define('call_for_price_website.create_call_form', function(require) { + "use strict"; const rpc = require('web.rpc'); var core = require('web.core'); + var Dialog = require('web.Dialog'); + var publicWidget = require('web.public.widget'); - $('#send_btn').on('click', function(){ - var first = $('#first_name').val(); - var last = $('#last_name').val(); - var product_id = $('#product_id').val(); - var phone = $('#phone').val(); - var email = $('#email').val(); - var message = $('#message').val(); - var qty = $('#quantity').val(); - rpc.query({ - model: "call.price", - method: "create_form", - args:[first,last,product_id,phone,email,message,qty] - }).then(function (result) { - document.getElementById('alert_message').style.display = "block" + publicWidget.registry.CallForPrice = publicWidget.Widget.extend({ + selector: '.oe_website_sale', + events: { + 'click #send_btn': 'callForPrice', + 'click #button_call_for_price': 'modalShow', + 'click #call_modal_close': 'modalHide' + }, + callForPrice: function() { + var self = this; + var first = self.$el.find('#first_name').val(); + var last = self.$el.find('#last_name').val(); + var product_id = self.$el.find('#product_id').val(); + var phone = self.$el.find('#phone').val(); + var email = self.$el.find('#email').val(); + var message = self.$el.find('#message').val(); + var qty = self.$el.find('#quantity').val(); + /** + * Validate email address format using a regular expression. + * email - The email address to validate. + * returns - True if the email is valid, false otherwise. + */ + function validateEmail(email) { + // Email validation regex pattern + var emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; + return emailPattern.test(email); + } + /** + * Validate phone number format using a regular expression. + * phone - The phone number to validate. + * returns - True if the phone number is valid, false otherwise. + */ + function validatePhoneNumber(phone) { + // Phone number validation regex pattern (without alphabets) + var phonePattern = /^[^A-Za-z]*$/ + return phonePattern.test(phone); + } + if (first && phone) { + if (!$.isNumeric(qty)) { + var modal = new Dialog(null, { + title: "Warning", + $content: $('
').text("Quantity should be a numeric value."), + buttons: [{ + text: "Close", + close: true + }], + }); + modal.open(); + return; + } + if (!validateEmail(email)) { + var modal = new Dialog(null, { + title: "Warning", + $content: $('
').text("Please enter a valid email address."), + buttons: [{ + text: "Close", + close: true + }], + }); + modal.open(); + return; + } + if (!validatePhoneNumber(phone)) { + var modal = new Dialog(null, { + title: "Warning", + $content: $('
').text("Please enter a valid phone number."), + buttons: [{ + text: "Close", + close: true + }], + }); + modal.open(); + return; + } + rpc.query({ + model: "call.price", + method: "create_form", + args: [first, last, product_id, phone, email, message, qty] + }).then(function(result) { + self.$el.find('#alert_message')[0].style.display = "block" + self.$el.find('#call_for_price')[0].style.display = 'none'; + }); + } else { + var modal = new Dialog(null, { + title: "Warning", + $content: $('
').text("Please enter the required information."), + buttons: [{ + text: "Close", + close: true + }], }); + modal.open(); + } + }, + modalShow: function() { + this.resetFormFields(); + this.$el.find('#call_for_price')[0].style.display = 'block'; + }, + modalHide: function() { + this.$el.find('#call_for_price')[0].style.display = 'none'; + }, + resetFormFields: function() { + this.$el.find('#first_name').val(''); + this.$el.find('#last_name').val(''); + this.$el.find('#email').val(''); + this.$el.find('#phone').val(''); + this.$el.find('#quantity').val(''); + this.$el.find('#message').val(''); + }, + }); + return publicWidget.registry.CallForPrice; }); \ No newline at end of file diff --git a/call_for_price_website/static/src/js/variant_mixin.js b/call_for_price_website/static/src/js/variant_mixin.js new file mode 100644 index 000000000..deba7150a --- /dev/null +++ b/call_for_price_website/static/src/js/variant_mixin.js @@ -0,0 +1,69 @@ +/** + * CustomVariantMixin module for Odoo. + * This module extends the VariantMixin functionality from website_sale to handle custom behavior. + */ +odoo.define('call_for_price_website.CustomVariantMixin', function(require) { + 'use strict'; + + // Import the VariantMixin from website_sale module + var VariantMixin = require('website_sale.VariantMixin'); + // Store a reference to the original onChangeCombination function + const originalOnChangeCombination = VariantMixin._onChangeCombination; + // Override the onChangeCombination function to implement custom behavior + VariantMixin._onChangeCombination = function(ev, $parent, combination) { + const $pricePerUom = $parent.find(".o_base_unit_price:first .oe_currency_value"); + if ($pricePerUom) { + if (combination.is_combination_possible !== false && combination.base_unit_price != 0) { + $pricePerUom.parents(".o_base_unit_price_wrapper").removeClass("d-none"); + $pricePerUom.text(this._priceToStr(combination.base_unit_price)); + $parent.find(".oe_custom_base_unit:first").text(combination.base_unit_name); + } else { + $pricePerUom.parents(".o_base_unit_price_wrapper").addClass("d-none"); + } + } + // Triggers a new JS event with the correct payload, which is then handled + // by the google analytics tracking code. + // Indeed, every time another variant is selected, a new view_item event + // needs to be tracked by google analytics. + if ('product_tracking_info' in combination) { + const $product = $('#product_detail'); + $product.data('product-tracking-info', combination['product_tracking_info']); + $product.trigger('view_item_event', combination['product_tracking_info']); + } + const addToCart = $parent.find('#add_to_cart_wrap'); + const contactUsButton = $parent.find('#contact_us_wrapper'); + const productPrice = $parent.find('.product_price'); + const quantity = $parent.find('.css_quantity'); + const product_unavailable = $parent.find('#product_unavailable'); + const price_call_div = $parent.find('#price_call_hide'); + + if (combination.prevent_zero_price_sale) { + productPrice.removeClass('d-inline-block').addClass('d-none'); + quantity.removeClass('d-inline-flex').addClass('d-none'); + addToCart.removeClass('d-inline-flex').addClass('d-none'); + contactUsButton.removeClass('d-none').addClass('d-flex'); + product_unavailable.removeClass('d-none').addClass('d-flex') + } else if (combination.price_call) { + productPrice.removeClass('d-inline-block').addClass('d-none'); + quantity.removeClass('d-inline-flex').addClass('d-none'); + addToCart.removeClass('d-inline-flex').addClass('d-none'); + contactUsButton.removeClass('d-none').addClass('d-flex'); + price_call_div.removeClass('d-none').addClass('d-flex'); + this.$el.find('#add_to_cart')[0].style.display = "none"; + this.$el.find('#price_of_product')[0].style.display = "none"; + this.$el.find('#price_of_product')[0].style.display = "none"; + } else { + productPrice.removeClass('d-none').addClass('d-inline-block'); + quantity.removeClass('d-none').addClass('d-inline-flex'); + addToCart.removeClass('d-none').addClass('d-inline-flex'); + contactUsButton.removeClass('d-flex').addClass('d-none'); + product_unavailable.removeClass('d-flex').addClass('d-none') + price_call_div.removeClass('d-flex').addClass('d-none') + this.$el.find('#add_to_cart')[0].style.display = "block"; + this.$el.find('#price_of_product')[0].style.display = "block"; + this.$el.find('#price_of_product')[0].style.display = "block"; + } + // Call the original onChangeCombination function + originalOnChangeCombination.apply(this, [ev, $parent, combination]); + }; +}); \ No newline at end of file diff --git a/call_for_price_website/views/product_product_views.xml b/call_for_price_website/views/product_product_views.xml new file mode 100644 index 000000000..98d091206 --- /dev/null +++ b/call_for_price_website/views/product_product_views.xml @@ -0,0 +1,16 @@ + + + + + + product.product.view.form.inherit.call.for.price.website + + product.product + + + + + + + + diff --git a/call_for_price_website/views/product_template_views.xml b/call_for_price_website/views/product_template_views.xml deleted file mode 100644 index 0447b7a59..000000000 --- a/call_for_price_website/views/product_template_views.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - product.template.view.form.inherit.call.for.price.website - product.template - - - - - - - - diff --git a/call_for_price_website/views/shop_hide_call_price_template.xml b/call_for_price_website/views/shop_hide_call_price_template.xml index a93e9d082..a98d1fd58 100644 --- a/call_for_price_website/views/shop_hide_call_price_template.xml +++ b/call_for_price_website/views/shop_hide_call_price_template.xml @@ -1,176 +1,172 @@ - - + + diff --git a/call_for_price_website/views/wishlist_hide_price_template.xml b/call_for_price_website/views/wishlist_hide_price_template.xml index 837211c35..e5d98b14b 100644 --- a/call_for_price_website/views/wishlist_hide_price_template.xml +++ b/call_for_price_website/views/wishlist_hide_price_template.xml @@ -35,4 +35,4 @@ - \ No newline at end of file +