@ -0,0 +1,57 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################### |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
||||
|
# 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 <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################### |
||||
|
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") |
@ -1,32 +0,0 @@ |
|||||
# -*- coding: utf-8 -*- |
|
||||
############################################################################### |
|
||||
# |
|
||||
# Cybrosys Technologies Pvt. Ltd. |
|
||||
# |
|
||||
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|
||||
# 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 <http://www.gnu.org/licenses/>. |
|
||||
# |
|
||||
############################################################################### |
|
||||
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") |
|
After Width: | Height: | Size: 177 KiB |
After Width: | Height: | Size: 388 KiB |
After Width: | Height: | Size: 171 KiB |
After Width: | Height: | Size: 182 KiB |
After Width: | Height: | Size: 179 KiB |
After Width: | Height: | Size: 142 KiB |
After Width: | Height: | Size: 192 KiB |
After Width: | Height: | Size: 89 KiB |
Before Width: | Height: | Size: 101 KiB |
Before Width: | Height: | Size: 307 KiB |
Before Width: | Height: | Size: 128 KiB |
Before Width: | Height: | Size: 143 KiB |
Before Width: | Height: | Size: 274 KiB |
Before Width: | Height: | Size: 213 KiB |
Before Width: | Height: | Size: 298 KiB |
Before Width: | Height: | Size: 48 KiB |
Before Width: | Height: | Size: 266 KiB After Width: | Height: | Size: 278 KiB |
@ -1,26 +1,122 @@ |
|||||
/** |
/** |
||||
* This file is used to give a success alert after requesting a call for price. |
* 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) { |
||||
odoo.define('call_for_price_website.create', function (require) { |
"use strict"; |
||||
"use strict"; |
|
||||
const rpc = require('web.rpc'); |
const rpc = require('web.rpc'); |
||||
var core = require('web.core'); |
var core = require('web.core'); |
||||
|
var Dialog = require('web.Dialog'); |
||||
|
var publicWidget = require('web.public.widget'); |
||||
|
|
||||
$('#send_btn').on('click', function(){ |
publicWidget.registry.CallForPrice = publicWidget.Widget.extend({ |
||||
var first = $('#first_name').val(); |
selector: '.oe_website_sale', |
||||
var last = $('#last_name').val(); |
events: { |
||||
var product_id = $('#product_id').val(); |
'click #send_btn': 'callForPrice', |
||||
var phone = $('#phone').val(); |
'click #button_call_for_price': 'modalShow', |
||||
var email = $('#email').val(); |
'click #call_modal_close': 'modalHide' |
||||
var message = $('#message').val(); |
}, |
||||
var qty = $('#quantity').val(); |
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: $('<div>').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: $('<div>').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: $('<div>').text("Please enter a valid phone number."), |
||||
|
buttons: [{ |
||||
|
text: "Close", |
||||
|
close: true |
||||
|
}], |
||||
|
}); |
||||
|
modal.open(); |
||||
|
return; |
||||
|
} |
||||
rpc.query({ |
rpc.query({ |
||||
model: "call.price", |
model: "call.price", |
||||
method: "create_form", |
method: "create_form", |
||||
args:[first,last,product_id,phone,email,message,qty] |
args: [first, last, product_id, phone, email, message, qty] |
||||
}).then(function (result) { |
}).then(function(result) { |
||||
document.getElementById('alert_message').style.display = "block" |
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: $('<div>').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; |
||||
}); |
}); |
@ -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]); |
||||
|
}; |
||||
|
}); |
@ -0,0 +1,16 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8" ?> |
||||
|
<odoo> |
||||
|
<!-- Inheriting product variant view form to add the 'call for price' field --> |
||||
|
<record id="product_normal_form_view" model="ir.ui.view"> |
||||
|
<field name="name"> |
||||
|
product.product.view.form.inherit.call.for.price.website |
||||
|
</field> |
||||
|
<field name="model">product.product</field> |
||||
|
<field name="inherit_id" ref="product.product_normal_form_view"/> |
||||
|
<field name="arch" type="xml"> |
||||
|
<xpath expr="//field[@name='public_categ_ids']" position="after"> |
||||
|
<field name="price_call"/> |
||||
|
</xpath> |
||||
|
</field> |
||||
|
</record> |
||||
|
</odoo> |
@ -1,14 +0,0 @@ |
|||||
<?xml version="1.0" encoding="UTF-8" ?> |
|
||||
<odoo> |
|
||||
<!--This file is used to add a field on product variants for hiding price--> |
|
||||
<record id="product_template_view_form" model="ir.ui.view"> |
|
||||
<field name="name">product.template.view.form.inherit.call.for.price.website</field> |
|
||||
<field name="model">product.template</field> |
|
||||
<field name="inherit_id" ref="website_sale.product_template_only_website_form_view"/> |
|
||||
<field name="arch" type="xml"> |
|
||||
<xpath expr="//field[@name='public_categ_ids']" position="after"> |
|
||||
<field name="price_call"/> |
|
||||
</xpath> |
|
||||
</field> |
|
||||
</record> |
|
||||
</odoo> |
|