diff --git a/website_bargain/README.rst b/website_bargain/README.rst new file mode 100644 index 000000000..b2471e9ce --- /dev/null +++ b/website_bargain/README.rst @@ -0,0 +1,44 @@ +.. image:: https://img.shields.io/badge/license-LGPL--3-green.svg + :target: https://www.gnu.org/licenses/lgpl-3.0-standalone.html + :alt: License: LGPL-3 + +Product Bidding In ECommerce +============================ +This module helps you to add auction in website sale. + +Configuration +============= +* No additional configurations needed + +Company +------- +* `Cybrosys Techno Solutions `__ + +License +------- +Lesser General Public License, Version 3 (LGPL v3). +(http://www.gnu.org/licenses/lgpl-3.0-standalone.html) + +Credits +------- +* Developers: (V17) Anfas Faisal K, Contact:odoo@cybrosys.com + +Contacts +-------- +* Mail Contact : odoo@cybrosys.com +* Website : https://cybrosys.com + +Bug Tracker +----------- +Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. + +Maintainer +========== +.. image:: https://cybrosys.com/images/logo.png + :target: https://cybrosys.com +This module is maintained by Cybrosys Technologies. +For support and more information, please visit `Our Website `__ + +Further information +=================== +HTML Description: ``__ diff --git a/website_bargain/__init__.py b/website_bargain/__init__.py new file mode 100644 index 000000000..6c1064fda --- /dev/null +++ b/website_bargain/__init__.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +############################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies() +# Author: Anfas Faisal K (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL 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 LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################### +from . import controllers +from . import models diff --git a/website_bargain/__manifest__.py b/website_bargain/__manifest__.py new file mode 100644 index 000000000..e4b29c3c9 --- /dev/null +++ b/website_bargain/__manifest__.py @@ -0,0 +1,60 @@ +# -*- coding: utf-8 -*- +############################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies() +# Author: Anfas Faisal K (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL 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 LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################### +{ + 'name': 'Product Bidding In ECommerce', + 'version': '17.0.1.0.0', + 'category': 'Website', + 'summary': 'App To Add Bidding option In Website', + 'description': 'Website Bargain is an application where users can create ' + 'and manage bargains on their website, enabling their ' + 'customers to participate in bidding and negotiate prices ' + 'for products or services', + 'author': 'Cybrosys Techno Solution', + 'company': 'Cybrosys Techno Solutions', + 'maintainer': 'Cybrosys Techno Solution', + 'website': 'https://www.cybrosys.com', + 'depends': ['website_sale', 'contacts'], + 'data': [ + 'security/ir.model.access.csv', + 'data/ir_cron_data.xml', + 'data/mail_template_data.xml', + 'views/website_bargain_views.xml', + 'views/bargain_template_views.xml', + 'views/bargain_information_views.xml', + 'views/bargain_subscribers_views.xml', + 'views/product_template_views.xml', + 'views/website_shop_auction_templates.xml', + 'views/website_product_views_templates.xml', + 'views/website_bargain_menus.xml', + 'views/bidders_information_templates.xml' + ], + 'assets': { + 'web.assets_frontend': [ + 'website_bargain/static/src/js/website_bargain.js', + 'website_bargain/static/src/css/website_product_bargain.css', + ]}, + 'images': ['static/description/banner.jpg'], + 'license': 'LGPL-3', + 'installable': True, + 'auto-install': False, + 'application': False, +} diff --git a/website_bargain/controllers/__init__.py b/website_bargain/controllers/__init__.py new file mode 100644 index 000000000..53393f742 --- /dev/null +++ b/website_bargain/controllers/__init__.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +############################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies() +# Author: Anfas Faisal K (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL 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 LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################### +from . import website_bargain diff --git a/website_bargain/controllers/website_bargain.py b/website_bargain/controllers/website_bargain.py new file mode 100644 index 000000000..27dd55bb3 --- /dev/null +++ b/website_bargain/controllers/website_bargain.py @@ -0,0 +1,353 @@ +# -*- coding: utf-8 -*- +############################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies() +# Author: Anfas Faisal K (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL 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 LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################### +from odoo import fields, http +from odoo.addons.website_sale.controllers.main import WebsiteSale +from odoo.http import request + + +class WebsiteAuction(WebsiteSale): + """This class enables is used to view the timer and related functions + of bidding,buy now and other routes + _prepare_product_values(self, product, category, search, **kwargs): + This function is inbuilt function in website sale and its + supered here and pass auction values in this function + auction_timer(self, auction_id): + This function gets the auction id and pass auction timing + details to website + buy_now(self, auction_id, product_id): + Its the function for button in buy now,in this function a new + sale order is created and send to the customer through email + def auction_close(self, auction_id): + Function gets the auction id and move the auction stage to + finished and make the product unavailable from website + winner_sale_order(self, auction_id, **post): + Makes a sale order to the winner and id notifications are + enabled it will send a email to the winners or losers + subscribe(self, auction_id, **post): + Used to add subscribers from website to database + place_bid(self, auction_id, **post): + When place bid button is triggered it will call this function + and the bidders details will be added to database and + if enabled it will send notification to subscribers + bidders(self, product_id): + Route to pass bidders details to website + bid_cancel(self, bidders): + Function to cancel the bid""" + + def _prepare_product_values(self, product, category, search, **kwargs): + """Summary: + Function is used to pass auction details by supering + this function because its already defined it websitesale + Args: + product:pass the object product + category:pass the category if enabled + kwargs:used to pass variable to function + Return: + Values is updated with auction and current website and + passed to website sale""" + values = super()._prepare_product_values(product, category, search, + **kwargs) + current_website = request.website + auction = request.env['website.bargain'].sudo().search_read([]) + values.update({ + 'auction': auction, + 'website': current_website + }) + return values + + @http.route('/auction/timer', type='json', auth='user', csrf=False) + def auction_timer(self, auction_id): + """Summary: + Function to pass timer details from auction like start + time,end time,extended time + Args: + auction_id:used to get auction id from website + Return: + Values which include start_time,end time,extended + time and state id""" + auction = request.env['website.bargain'].sudo().browse(int(auction_id)) + values = { + 'start_time': auction.start_time, + 'end_time': fields.Datetime.context_timestamp(auction, + auction.end_time), + 'state': auction.state, + } + if auction.extend_time: + values['extend_time'] = fields.Datetime.context_timestamp(auction, + auction.extend_time) + return values + + @http.route('/auction/close', type='json', auth='user', csrf=False) + def auction_close(self, auction_id): + """Summary: + Function to close auction when a customer buys + a product instantly or the auction is ended + Args: + auction_id: used to get auction id from website + Return: + a string auction ended to website""" + auction = request.env['website.bargain'].sudo().browse(int(auction_id)) + auction.product_id.is_auction = False + auction.product_id.is_published = False + auction.write({'state': 'finished'}) + return "auction ended" + + @http.route('/place_bid', type='json', auth='user', csrf=False) + def place_bid(self, auction_id, **post): + """Summary: + When place bid button is clicked it will trigger this function + and will add bidders details to backend and will send + notification to the subscribers if its enabled + Args: + auction_id:used to get auction id from website + post:used to get bid amount from frontend + Return: + A message bid placed and suction details""" + bid_amount = post.get('bid_amount') + auction = request.env['website.bargain'].sudo().browse(int(auction_id)) + bidder_total = auction.bargain_information_ids.search_count( + [('bidder_id', '=', request.env.user.partner_id.id), + ('bid_offer', '=', bid_amount)]) + if bidder_total >= 1: + return False + else: + auction.bargain_information_ids.sudo().create({ + 'bidder_id': request.env.user.partner_id.id, + 'auction_id': auction.id, + 'bid_offer': bid_amount, + 'status': 'Bid Placed' + }) + if auction.is_subscriber_start_notification and not auction.is_send_mail: + data = 'Bidding has started for ' + auction.name + '. Please check our website for more details.' + subscribers = "" + for record in auction.bargain_subscribers_ids: + subscribers += record.subscriber_id.email + ',' + email_values = {'email_from': auction.auction_manager_id.email, + 'subject': 'Bidding Started for ' + auction.name, + 'email_to': subscribers, 'body_html': data} + request.env['mail.mail'].sudo().create(email_values).send() + auction.is_send_mail = True + auction.write({'is_send_mail': True}) + + if auction.is_new_bid_notification: + data = 'A new bid has been placed with amount ' + str( + bid_amount) + ',on ' \ + + auction.name + ',by ' + request.env.user.partner_id.name \ + + 'please check into ' \ + 'our website' + subscribers = " " + for record in auction.bargain_subscribers_ids: + subscribers += record.subscriber_id.email + ',' + email_values = {'email_from': auction.auction_manager_id.email, + 'subject': 'New Bid Placed on ' + auction.name, + 'email_to': subscribers, 'body_html': data} + request.env['mail.mail'].sudo().create(email_values).send() + values = ({ + 'bid_placed': 'Bid Placed', + 'auction': auction + }) + + return values + + @http.route('/bidders/', type='http', + auth='user', csrf=False, website=True) + def bidders(self, product_id): + """ + This method is used to fetch the details of the bidders participating in + an auction and render them on the website. + Args: + product_id: A product template model object. + Returns: + A rendered HTML template with information about the bidders in the + auction.""" + auction = request.env['website.bargain'].sudo().search( + [('product_id', '=', product_id.id), ('state', '=', 'running')]) + bidders_information = request.env['bargain.information'].sudo().search( + [('auction_id', '=', auction.id)], + order='bid_offer desc') + values = ({ + 'bidders_information': bidders_information, + 'product_id': product_id, + }) + return request.render('website_bargain.bidders_information', values) + + @http.route('/bid/cancel/', + type='http', auth='user', csrf='false') + def bid_cancel(self, bidders): + """This function is for cancel the bid + Args: + bidders:Bidders name will be getting here + Returns:It returns previous page""" + bidders.status = 'cancelled' + previous_web_url = request.httprequest.headers.get('referer') + return request.redirect(previous_web_url) + + @http.route('/shop/sale/order', type='json', auth='public', website=True, + csrf=False) + def winner_sale_order(self, auction_id, **post): + """ + This route creates a draft sale order for the winner of an auction + and sends notifications for winning and losing. + Args: + auction_id: the ID of the auction obtained from the frontend + post: used to get data of product from frontend + Returns: + True""" + # Get the ID of the product from the post data + product_product_id = post.get('product_product_id') + # Find the auction with the given ID + auction = request.env['website.bargain'].sudo().browse(int(auction_id)) + auction.write({'state': 'finished'}) + if auction.is_bid_end_notification: + data = 'Bidding has ended for ' + auction.name + '. Thank you for participating.' + subscribers = "" + for record in auction.bargain_subscribers_ids: + subscribers += record.subscriber_id.email + ',' + email_values = {'email_from': auction.auction_manager_id.email, + 'subject': 'Bidding Ended for ' + auction.name, + 'email_to': subscribers, 'body_html': data} + request.env['mail.mail'].sudo().create(email_values).send() + # Find the highest bidder for the auction + bid_record = auction.bargain_information_ids.filtered( + lambda r: r.status == 'Bid Placed').sorted( + key=lambda r: r.bid_offer)[-1] + # Create a draft sale order for the winner + sale_order = request.env['sale.order'].sudo().create({ + 'partner_id': bid_record.bidder_id.id, + 'state': 'draft', + }) + # Add the product to the sale order and set the price to the bid offer + sale_order.sudo().write({ + 'order_line': [(0, 0, { + 'product_id': int(product_product_id), + 'product_uom_qty': 1, + 'price_unit': bid_record.bid_offer, + 'name': 'auction won', + })] + }) + mail_compose_message = request.env['mail.compose.message'] + so_mcm_vals = sale_order.sudo().action_quotation_send().get('context', + {}) + compose_msg = mail_compose_message.sudo().with_context( + so_mcm_vals).create({}) + compose_msg.sudo().action_send_mail() + # Send a notification email to the winner and/or losers, if enabled + if auction.is_winner_notification: + data = "You have won in " + auction.name + " Kindly pay now and" \ + " collect the product " \ + "from our website" + email_values = { + 'email_from': auction.auction_manager_id.email, + 'subject': 'Won ' + auction.name, + 'email_to': bid_record.bidder_id.email, + 'body_html': data + } + request.env['mail.mail'].sudo().create(email_values).send() + if auction.is_loser_notification: + data = "You have lost in " + auction.name + "Better luck next time"\ + " thank you for your " \ + "effort and time" + email_to = '' + for record in auction.bargain_information_ids: + if record.bidder_id.id != bid_record.bidder_id.id: + email_to += record.bidder_id.email + ',' + email_values = { + 'email_from': auction.auction_manager_id.email, + 'subject': 'Lost ' + auction.name, + 'email_to': email_to, + 'body_html': data + } + request.env['mail.mail'].sudo().create(email_values).send() + return True + + @http.route('/subscribe/bid', type='json', auth='user', csrf=False) + def subscribe(self, auction_id, **post): + """ + Endpoint to manage subscription to an auction + auction_id: integer ID of the auction being subscribed to/unsubscribed + text: string indicating whether the user is subscribing or + unsubscribing ('subscribe' or 'unsubscribe') + return: string message indicating success or failure of + subscription/unsubscription action + """ + text = post.get('text') + auction = request.env['website.bargain'].sudo().browse(int(auction_id)) + if text == 'subscribe': + if request.env.user.partner_id in \ + auction.bargain_subscribers_ids.subscriber_id: + return 'You have already subscribed' + auction.bargain_subscribers_ids.sudo().create({ + 'subscriber_id': request.env.user.partner_id.id, + 'auction_id': auction.id, + 'is_subscribed': True + }) + return 'You have been successfully subscribed to this auction' + elif text == 'unsubscribe': + auction.bargain_subscribers_ids.sudo().search( + [('subscriber_id', '=', request.env.user.partner_id.id), + ('auction_id', '=', auction.id)]).unlink() + return 'Unsubscribed successfully' + + @http.route('/subscribe/status', type='json', auth='user', csrf=False) + def subscribe_status(self, auction_id, **post): + """ + Controller method to handle subscription to an auction. + """ + auction = request.env['website.bargain'].sudo().browse(int(auction_id)) + is_subscribed = False + for subscriber in auction.bargain_subscribers_ids: + if subscriber.subscriber_id == request.env.user.partner_id: + is_subscribed = subscriber.is_subscribed + break + + return is_subscribed + + @http.route('/buy/now', type='json', auth='public', website=True, + csrf=False) + def buy_now(self, auction_id, product_id): + """ + Args: + auction_id: the ID of the auction obtained from the frontend + product_id: the ID of the product used to get data from the frontend + """ + # Find the auction with the given ID + auction = request.env['website.bargain'].sudo().browse(int(auction_id)) + # Create a draft sale order for the winner + sale_order = request.env['sale.order'].sudo().create({ + 'partner_id': request.env.user.partner_id.id, + 'state': 'draft', + }) + sale_order.sudo().write({ + 'order_line': [(0, 0, { + 'product_id': int(product_id), + 'product_uom_qty': 1, + 'name': '(auction won)' + auction.name, + 'price_unit': auction.price_buy_now, + })] + }) + # Send a notification email to the winner + mail_compose_message = request.env['mail.compose.message'] + so_mcm_vals = sale_order.sudo().action_quotation_send().get('context', + {}) + compose_msg = mail_compose_message.sudo().with_context( + so_mcm_vals).create({}) + compose_msg.sudo().action_send_mail() diff --git a/website_bargain/data/ir_cron_data.xml b/website_bargain/data/ir_cron_data.xml new file mode 100644 index 000000000..20f72d940 --- /dev/null +++ b/website_bargain/data/ir_cron_data.xml @@ -0,0 +1,25 @@ + + + + + Auction: Email Notification + + code + model.send_email_notification() + 1 + minutes + -1 + + + + + Auction: Auto Start + + code + model.auction_auto_start() + 1 + minutes + -1 + + + diff --git a/website_bargain/data/mail_template_data.xml b/website_bargain/data/mail_template_data.xml new file mode 100644 index 000000000..c1d590a58 --- /dev/null +++ b/website_bargain/data/mail_template_data.xml @@ -0,0 +1,104 @@ + + + + + Auction: Admin Notification Email + + {{ + (object.auction_manager_id.partner_id.email) }} + + {{ + (object.auction_manager_id.partner_id.email) }} + + {{ (object.name) }} end time is near + +
+

+ Dear + + + +
+
+ This mail is a reminder that + + + Auction + + + will end at + + End Time + + + .So if its need to be + extended kindly reminding you to extend it fast. +

+
+
+
+ + + Auction: Auction Start Notification Email + + {{ + (object.auction_manager_id.partner_id.email) }} + + {{ (object.name) }} has started + +
+

+ Dear Sir/Madam +
+
+ This mail is a reminder that + + + Auction + + + has started + + Start Time Time + + + .Place your bids and win the auction. +

+
+
+
+ + + Auction: Auction Extend Notification Email + + + {{ + (object.auction_manager_id.partner_id.email) }} + + {{ (object.name) }} has extended + +
+

+ Dear Sir/Madam +
+
+ This mail is a reminder that + + + Auction + + + has extended + + Extended Time Time + + + .Place your bids and win the auction. +

+
+
+
+
diff --git a/website_bargain/doc/RELEASE_NOTES.md b/website_bargain/doc/RELEASE_NOTES.md new file mode 100644 index 000000000..b87a0dbd9 --- /dev/null +++ b/website_bargain/doc/RELEASE_NOTES.md @@ -0,0 +1,7 @@ +## Module + +#### 05.04.2024 +#### Version 17.0.1.0.0 +#### ADD + +- Initial Commit for Product Bidding In ECommerce diff --git a/website_bargain/models/__init__.py b/website_bargain/models/__init__.py new file mode 100644 index 000000000..39f685953 --- /dev/null +++ b/website_bargain/models/__init__.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +############################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies() +# Author: Anfas Faisal K (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL 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 LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################### +from . import bargain_information +from . import bargain_subscribers +from . import bargain_template +from . import product_template +from . import website_bargain diff --git a/website_bargain/models/bargain_information.py b/website_bargain/models/bargain_information.py new file mode 100644 index 000000000..b86a093e2 --- /dev/null +++ b/website_bargain/models/bargain_information.py @@ -0,0 +1,44 @@ +# -*- coding: utf-8 -*- +############################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies() +# Author: Anfas Faisal K (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL 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 LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################### +from odoo import fields, models + + +class BargainInformation(models.Model): + """Class for adding bidder details to the database""" + _name = 'bargain.information' + _rec_name = 'auction_id' + _description = "Bidder Details" + _inherit = ['mail.thread', 'mail.activity.mixin'] + + bidder_id = fields.Many2one('res.partner', string='Bidder', required=True, + help="Bidders details") + auction_id = fields.Many2one('website.bargain', string='Auction', + required=True, help="Auction Details") + currency_id = fields.Many2one(related="auction_id.currency_id", + help="Currency Details") + bid_offer = fields.Monetary(string="Bid Offer", + currency_field='currency_id', + help="Offered amount") + status = fields.Char(string="Status", readonly=True, + help="Current Status of bid") + product_id = fields.Many2one(related='auction_id.product_id', + string='Product', help="Product details") diff --git a/website_bargain/models/bargain_subscribers.py b/website_bargain/models/bargain_subscribers.py new file mode 100644 index 000000000..7f3f33cab --- /dev/null +++ b/website_bargain/models/bargain_subscribers.py @@ -0,0 +1,45 @@ +# -*- coding: utf-8 -*- +############################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies() +# Author: Anfas Faisal K (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL 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 LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################### +from odoo import fields, models + + +class BargainSubscribers(models.Model): + """Model for adding the subscriber details """ + _name = 'bargain.subscribers' + _inherit = ['mail.thread', 'mail.activity.mixin'] + _description = "Subscriber details" + + subscriber_id = fields.Many2one('res.partner', required=True, + help="Subscribers id will be here ") + name = fields.Char(related='subscriber_id.name', string='Name', + readonly=False, help="Subscribers name", + required=True) + email = fields.Char(related='subscriber_id.email', string='Email', + readonly=False, help="Subscribers email") + auction_id = fields.Many2one('website.bargain', string='Auction', + required=True, help="Auction details") + subscribe_time = fields.Datetime(string='Subscribe On', + default=fields.Datetime.today(), + readonly=True, + help="Time of subscription") + is_subscribed = fields.Boolean(string="Is Subscribed", + help="Check if Subscribed or not") diff --git a/website_bargain/models/bargain_template.py b/website_bargain/models/bargain_template.py new file mode 100644 index 000000000..9f7030438 --- /dev/null +++ b/website_bargain/models/bargain_template.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +############################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies() +# Author: Anfas Faisal K (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL 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 LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################### +from odoo import fields, models + + +class BargainTemplate(models.Model): + """Model for auction template""" + + _name = 'bargain.template' + _inherit = ['mail.thread', 'mail.activity.mixin'] + _description = "Bargain Template" + + name = fields.Char(string='Template Name', help="Name of the template") + product_id = fields.Many2one('product.template', + domain=[('is_published', '=', True)], + required=True, + help="Choose the product from the list") diff --git a/website_bargain/models/product_template.py b/website_bargain/models/product_template.py new file mode 100644 index 000000000..59b6e71c4 --- /dev/null +++ b/website_bargain/models/product_template.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- +############################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies() +# Author: Anfas Faisal K (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL 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 LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################### +from odoo import fields, models + + +class ProductTemplateInherit(models.Model): + """Model to add a new boolean field to product template""" + _inherit = 'product.template' + + is_auction = fields.Boolean(string='Auction On', readonly=True, + help="If auction is on this field will be true" + ) diff --git a/website_bargain/models/website_bargain.py b/website_bargain/models/website_bargain.py new file mode 100644 index 000000000..0cce0c771 --- /dev/null +++ b/website_bargain/models/website_bargain.py @@ -0,0 +1,301 @@ +# -*- coding: utf-8 -*- +############################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies() +# Author: Anfas Faisal K (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL 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 LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################### +from datetime import timedelta +from odoo import api, fields, models, _ +from odoo.exceptions import ValidationError + + +class WebsiteBargain(models.Model): + """This is the main class of website bargain where all the details are + stored in this model + _onchange_template_id: + function for automatically add the auction name + _check_end_date: + function to validate the end date if it is higher than the start + date + _check_extend_time: + function to validate extended time weather it is greater than end + time and after saving will send notification to subscribers if + enabled + action_confirm: + button function to confirm auction and will make product as + published + action_reset_to_draft: + button function to reset the auction to draft + action_run_auction: + button function to start auction manually + action_complete: + button function to end auction manually + action_close: + button function to close auction + send_email_notification: + Function for sending auction notification for admin + before ending if enabled + auction_auto_start: + Cron function for auction auto start when its start + time and also will send notification to customers about auction + """ + _name = 'website.bargain' + _description = "Website Bargain" + _inherit = ['mail.thread', 'mail.activity.mixin'] + + website_id = fields.Many2one('website', string='Website', required=True, + help="Add website here to put auction") + template_id = fields.Many2one('bargain.template', string='Template', + help="add already created templates of " + "auction with products") + auction_manager_id = fields.Many2one('res.users', string="Auction Manager", + help="Set suction manager here", + required=True) + product_id = fields.Many2one(related='template_id.product_id', store=True, + string='Product', readonly=False, + help="Select the product", required=True) + name = fields.Char(string='Auction Name', help="Auctions name") + currency_id = fields.Many2one('res.currency', 'Currency', + default=lambda + self: self.env.user.company_id.currency_id.id, + required=True, + help="if you select this " + "currency bidding will " + "be on that currency itself") + initial_price = fields.Monetary(string='Initial Price', + currency_field='currency_id', + required=True, + help="Minimum amount required to bid") + is_buy_now = fields.Boolean(string='Provide buy now button', + help='Enable a button for buying instantly') + price_buy_now = fields.Monetary(string='Buy Now Price', + currency_field='currency_id', + help="Price of the product if its" + " immediately buying") + start_time = fields.Datetime(string='Start Date Time', required=True, + default=fields.Datetime.today(), + help="Auction start time") + end_time = fields.Datetime(string='End Date Time', required=True, + help="Auction start time") + extend_time = fields.Datetime(string="Extended Time", + help="By setting days you can " + "extend the auction") + state = fields.Selection( + [('draft', "Draft"), ('confirmed', "Confirmed"), + ('running', "Running"), + ('closed', "Closed"), ('finished', "Finished")], default='draft') + bargain_information_ids = fields.One2many('bargain.information', + 'auction_id', readonly=True) + bargain_subscribers_ids = fields.One2many('bargain.subscribers', + 'auction_id') + is_activate = fields.Boolean(string='Activate', + help='this will activate ' + 'notification for the admins') + notify_on = fields.Integer(string='Notify before', default='5', + help="Set notification time here") + notify_selection = fields.Selection( + [('days', "Days"), ('hours', "Hours"), ('minutes', "Minutes"), + ('seconds', "Seconds")], default='minutes') + is_notification_send = fields.Boolean(string='Notification Send', + help='If notification send manually ' + 'you can enable this field ' + 'to restrict ' + 'sending notification before ' + 'the time added') + is_winner_notification = fields.Boolean( + string='Send Notification to Winner', + help='Enable this option to send notification to the winner') + is_loser_notification = fields.Boolean(string='Send Notification to Loser', + help='Enable this option to send ' + 'notification to the losers') + is_subscriber_start_notification = fields.Boolean(string='Bidding Start', + help="Send subscribers " + "the bidding start " + "notification") + is_send_mail = fields.Boolean(string='Bidding Started Mail Sent', + help='If Bidding mail has been sent to customer') + is_extend_auction_notification = fields.Boolean(string='Auction Extended', + help="Send subscribers the" + "bidding extended " + "notification") + is_new_bid_notification = fields.Boolean(string='New Bid Placed', + help="Send subscribers " + "notifications if new bids" + " are placed") + is_bid_end_notification = fields.Boolean(string='Auction Finished', + help="Send subscribers " + "notifications if bidding " + "is over") + product_img = fields.Binary(related="product_id.image_1920") + product_description = fields.Text(related="product_id.description_sale", + string="Auction Product Description") + + @api.onchange('template_id', 'product_id') + def _onchange_template_id(self): + """summary: + function to add name automatically""" + if self.product_id: + self.name = f"Auction for {self.product_id.name}" + + @api.constrains('end_time', 'start_time') + def _check_end_date(self): + """ + Summary: + start and end date validation function + """ + if self.end_time <= self.start_time: + raise ValidationError( + _('End time should be greater than start time')) + + @api.constrains('extend_time') + def _check_extend_time(self): + """Summary: + function to validate extended time weather it is greater than + end time and after saving will send notification to subscribers + if enabled""" + if self.extend_time: + if self.extend_time <= self.end_time: + raise ValidationError( + _('This time is not greater than the old time(' + str( + self.end_time) + ')')) + if self.is_extend_auction_notification: + template_id = self.env.ref( + 'website_bargain.email_template_auction_extended') + email_to = '' + for subscriber in self.bargain_subscribers_ids: + email_to += subscriber.email + ',' + template_id.email_to = email_to + template_id.send_mail(self.id, force_send=True) + + def action_confirm(self): + """ + Summary: + button function to confirm auction and will + make product as published + """ + if self.search([('product_id', '=', self.product_id.id), + ('state', '=', 'running')]): + raise ValidationError( + _('Already an auction is running for this product please' + ' close it to continue')) + if self.end_time <= fields.Datetime.today(): + raise ValidationError(_('End time is already over')) + self.product_id.is_published = True + self.product_id.website_id = self.website_id + self.write({'state': 'confirmed'}) + + def action_reset_to_draft(self): + """ + Summary: + button function to reset the auction to draft + """ + self.product_id.is_auction = False + self.write({'state': 'draft'}) + + def action_run_auction(self): + """ + Summary: + button function to start auction manually + """ + if self.search([('product_id', '=', self.product_id.id), + ('state', '=', 'running')]): + raise ValidationError( + _('Already an auction is running for this product ' + 'please close it to continue')) + self.product_id.is_auction = True + self.write({'state': 'running'}) + + def action_complete(self): + """ + Summary: + button function to end auction manually + """ + self.product_id.is_auction = False + self.product_id.is_published = False + self.write({'state': 'finished'}) + + def action_close(self): + """ + Summary: + button function to close auction + """ + self.product_id.is_auction = False + self.product_id.is_published = False + self.write({'state': 'closed'}) + + def send_email_notification(self): + """ + Summary: + Function for sending auction notification for admin e ending if + enabled + """ + # Get the email template for the admin notification + template_id = self.env.ref( + 'website_bargain.admin_email_template') + # Find all running auctions that have notification enabled and have + # not been sent yet + auctions = self.search([('state', '=', 'running'), + ('is_activate', '=', True), + ('notify_on', '>', 0), + ('is_notification_send', '=', False)]) + # Loop through the auctions that need to be notified + for auction in auctions: + # Map the time unit to a string for timedelta + time_unit_map = {'days': 'days', 'hours': 'hours', + 'minutes': 'minutes', 'seconds': 'seconds'} + time_unit = time_unit_map.get(auction.notify_selection) + # Check if it's time to send the notification + if time_unit: + next_notification = auction.end_time - timedelta( + **{time_unit: auction.notify_on}) + if next_notification <= fields.Datetime.today(): + # Send the notification email and set the flag to True + template_id.send_mail(auction.id, force_send=True) + auction.is_notification_send = True + + def auction_auto_start(self): + """ + Summary: + Cron function for auction auto start when its start + time and also will send notification to customers about auction + """ + # Get all confirmed auctions + auctions = self.search([('state', '=', 'confirmed')]) + # Get the email template for auction start notification + template_id = self.env.ref( + 'website_bargain.email_template_auction_start') + # Get the emails of all the bidders and sale order partners + bidders = self.env['bargain.information'].search([]).mapped( + 'bidder_id.email') + sale_orders_partner = self.env['sale.order'].search( + [('state', '=', 'sale')]).mapped('partner_id.email') + # Loop through the auctions and check if any auction's start time has arrived + for auction in auctions: + if auction.start_time <= fields.Datetime.today(): + # Set the product as an auction and update the website + auction.product_id.is_auction = True + auction.product.website_id = auction.website_id + auction.write({'state': 'running'}) + # Send email notifications to all the bidders and sale order partners + email_to = "" + for partner in sale_orders_partner: + email_to += partner + ',' + for bidder in bidders: + email_to += bidder + ',' + template_id.email_to = email_to + template_id.send_mail(auction.id, force_send=True) diff --git a/website_bargain/security/ir.model.access.csv b/website_bargain/security/ir.model.access.csv new file mode 100644 index 000000000..c4b619de7 --- /dev/null +++ b/website_bargain/security/ir.model.access.csv @@ -0,0 +1,5 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_website_bargain_user,website.bargain.user,model_website_bargain,base.group_user,1,1,1,1 +access_website_bargain_template_user,website.bargain.template.user,model_bargain_template,base.group_user,1,1,1,1 +access_website_bidder_information_user,bidder.information.user,model_bargain_information,base.group_user,1,1,1,1 +access_website_bargain_subscribers_user,bargain.subscribers.user,model_bargain_subscribers,base.group_user,1,1,1,1 diff --git a/website_bargain/static/description/assets/icons/check.png b/website_bargain/static/description/assets/icons/check.png new file mode 100644 index 000000000..c8e85f51d Binary files /dev/null and b/website_bargain/static/description/assets/icons/check.png differ diff --git a/website_bargain/static/description/assets/icons/chevron.png b/website_bargain/static/description/assets/icons/chevron.png new file mode 100644 index 000000000..2089293d6 Binary files /dev/null and b/website_bargain/static/description/assets/icons/chevron.png differ diff --git a/website_bargain/static/description/assets/icons/cogs.png b/website_bargain/static/description/assets/icons/cogs.png new file mode 100644 index 000000000..95d0bad62 Binary files /dev/null and b/website_bargain/static/description/assets/icons/cogs.png differ diff --git a/website_bargain/static/description/assets/icons/consultation.png b/website_bargain/static/description/assets/icons/consultation.png new file mode 100644 index 000000000..8319d4baa Binary files /dev/null and b/website_bargain/static/description/assets/icons/consultation.png differ diff --git a/website_bargain/static/description/assets/icons/ecom-black.png b/website_bargain/static/description/assets/icons/ecom-black.png new file mode 100644 index 000000000..a9385ff13 Binary files /dev/null and b/website_bargain/static/description/assets/icons/ecom-black.png differ diff --git a/website_bargain/static/description/assets/icons/education-black.png b/website_bargain/static/description/assets/icons/education-black.png new file mode 100644 index 000000000..3eb09b27b Binary files /dev/null and b/website_bargain/static/description/assets/icons/education-black.png differ diff --git a/website_bargain/static/description/assets/icons/hotel-black.png b/website_bargain/static/description/assets/icons/hotel-black.png new file mode 100644 index 000000000..130f613be Binary files /dev/null and b/website_bargain/static/description/assets/icons/hotel-black.png differ diff --git a/website_bargain/static/description/assets/icons/license.png b/website_bargain/static/description/assets/icons/license.png new file mode 100644 index 000000000..a5869797e Binary files /dev/null and b/website_bargain/static/description/assets/icons/license.png differ diff --git a/website_bargain/static/description/assets/icons/lifebuoy.png b/website_bargain/static/description/assets/icons/lifebuoy.png new file mode 100644 index 000000000..658d56ccc Binary files /dev/null and b/website_bargain/static/description/assets/icons/lifebuoy.png differ diff --git a/website_bargain/static/description/assets/icons/manufacturing-black.png b/website_bargain/static/description/assets/icons/manufacturing-black.png new file mode 100644 index 000000000..697eb0e9f Binary files /dev/null and b/website_bargain/static/description/assets/icons/manufacturing-black.png differ diff --git a/website_bargain/static/description/assets/icons/pos-black.png b/website_bargain/static/description/assets/icons/pos-black.png new file mode 100644 index 000000000..97c0f90c1 Binary files /dev/null and b/website_bargain/static/description/assets/icons/pos-black.png differ diff --git a/website_bargain/static/description/assets/icons/puzzle.png b/website_bargain/static/description/assets/icons/puzzle.png new file mode 100644 index 000000000..65cf854e7 Binary files /dev/null and b/website_bargain/static/description/assets/icons/puzzle.png differ diff --git a/website_bargain/static/description/assets/icons/restaurant-black.png b/website_bargain/static/description/assets/icons/restaurant-black.png new file mode 100644 index 000000000..4a35eb939 Binary files /dev/null and b/website_bargain/static/description/assets/icons/restaurant-black.png differ diff --git a/website_bargain/static/description/assets/icons/service-black.png b/website_bargain/static/description/assets/icons/service-black.png new file mode 100644 index 000000000..301ab51cb Binary files /dev/null and b/website_bargain/static/description/assets/icons/service-black.png differ diff --git a/website_bargain/static/description/assets/icons/trading-black.png b/website_bargain/static/description/assets/icons/trading-black.png new file mode 100644 index 000000000..9398ba2f1 Binary files /dev/null and b/website_bargain/static/description/assets/icons/trading-black.png differ diff --git a/website_bargain/static/description/assets/icons/training.png b/website_bargain/static/description/assets/icons/training.png new file mode 100644 index 000000000..884ca024d Binary files /dev/null and b/website_bargain/static/description/assets/icons/training.png differ diff --git a/website_bargain/static/description/assets/icons/update.png b/website_bargain/static/description/assets/icons/update.png new file mode 100644 index 000000000..ecbc5a01a Binary files /dev/null and b/website_bargain/static/description/assets/icons/update.png differ diff --git a/website_bargain/static/description/assets/icons/user.png b/website_bargain/static/description/assets/icons/user.png new file mode 100644 index 000000000..6ffb23d9f Binary files /dev/null and b/website_bargain/static/description/assets/icons/user.png differ diff --git a/website_bargain/static/description/assets/icons/wrench.png b/website_bargain/static/description/assets/icons/wrench.png new file mode 100644 index 000000000..6c04dea0f Binary files /dev/null and b/website_bargain/static/description/assets/icons/wrench.png differ diff --git a/website_bargain/static/description/assets/misc/Cybrosys_new.png b/website_bargain/static/description/assets/misc/Cybrosys_new.png new file mode 100644 index 000000000..da4058087 Binary files /dev/null and b/website_bargain/static/description/assets/misc/Cybrosys_new.png differ diff --git a/website_bargain/static/description/assets/misc/categories.png b/website_bargain/static/description/assets/misc/categories.png new file mode 100644 index 000000000..bedf1e0b1 Binary files /dev/null and b/website_bargain/static/description/assets/misc/categories.png differ diff --git a/website_bargain/static/description/assets/misc/check-box.png b/website_bargain/static/description/assets/misc/check-box.png new file mode 100644 index 000000000..42caf24b9 Binary files /dev/null and b/website_bargain/static/description/assets/misc/check-box.png differ diff --git a/website_bargain/static/description/assets/misc/compass.png b/website_bargain/static/description/assets/misc/compass.png new file mode 100644 index 000000000..d5fed8faa Binary files /dev/null and b/website_bargain/static/description/assets/misc/compass.png differ diff --git a/website_bargain/static/description/assets/misc/corporate.png b/website_bargain/static/description/assets/misc/corporate.png new file mode 100644 index 000000000..2eb13edbf Binary files /dev/null and b/website_bargain/static/description/assets/misc/corporate.png differ diff --git a/website_bargain/static/description/assets/misc/customer-support.png b/website_bargain/static/description/assets/misc/customer-support.png new file mode 100644 index 000000000..79efc72ed Binary files /dev/null and b/website_bargain/static/description/assets/misc/customer-support.png differ diff --git a/website_bargain/static/description/assets/misc/cybrosys-logo.png b/website_bargain/static/description/assets/misc/cybrosys-logo.png new file mode 100644 index 000000000..cc3cc0ccf Binary files /dev/null and b/website_bargain/static/description/assets/misc/cybrosys-logo.png differ diff --git a/website_bargain/static/description/assets/misc/features.png b/website_bargain/static/description/assets/misc/features.png new file mode 100644 index 000000000..b41769f77 Binary files /dev/null and b/website_bargain/static/description/assets/misc/features.png differ diff --git a/website_bargain/static/description/assets/misc/logo.png b/website_bargain/static/description/assets/misc/logo.png new file mode 100644 index 000000000..478462d3e Binary files /dev/null and b/website_bargain/static/description/assets/misc/logo.png differ diff --git a/website_bargain/static/description/assets/misc/pictures.png b/website_bargain/static/description/assets/misc/pictures.png new file mode 100644 index 000000000..56d255fe9 Binary files /dev/null and b/website_bargain/static/description/assets/misc/pictures.png differ diff --git a/website_bargain/static/description/assets/misc/pie-chart.png b/website_bargain/static/description/assets/misc/pie-chart.png new file mode 100644 index 000000000..426e05244 Binary files /dev/null and b/website_bargain/static/description/assets/misc/pie-chart.png differ diff --git a/website_bargain/static/description/assets/misc/right-arrow.png b/website_bargain/static/description/assets/misc/right-arrow.png new file mode 100644 index 000000000..730984a06 Binary files /dev/null and b/website_bargain/static/description/assets/misc/right-arrow.png differ diff --git a/website_bargain/static/description/assets/misc/star.png b/website_bargain/static/description/assets/misc/star.png new file mode 100644 index 000000000..2eb9ab29f Binary files /dev/null and b/website_bargain/static/description/assets/misc/star.png differ diff --git a/website_bargain/static/description/assets/misc/support.png b/website_bargain/static/description/assets/misc/support.png new file mode 100644 index 000000000..4f18b8b82 Binary files /dev/null and b/website_bargain/static/description/assets/misc/support.png differ diff --git a/website_bargain/static/description/assets/misc/whatsapp.png b/website_bargain/static/description/assets/misc/whatsapp.png new file mode 100644 index 000000000..d513a5356 Binary files /dev/null and b/website_bargain/static/description/assets/misc/whatsapp.png differ diff --git a/website_bargain/static/description/assets/modules/1.jpg b/website_bargain/static/description/assets/modules/1.jpg new file mode 100644 index 000000000..f3a24c620 Binary files /dev/null and b/website_bargain/static/description/assets/modules/1.jpg differ diff --git a/website_bargain/static/description/assets/modules/2.jpg b/website_bargain/static/description/assets/modules/2.jpg new file mode 100644 index 000000000..5d694c069 Binary files /dev/null and b/website_bargain/static/description/assets/modules/2.jpg differ diff --git a/website_bargain/static/description/assets/modules/3.jpg b/website_bargain/static/description/assets/modules/3.jpg new file mode 100644 index 000000000..9407e5e83 Binary files /dev/null and b/website_bargain/static/description/assets/modules/3.jpg differ diff --git a/website_bargain/static/description/assets/modules/4.jpg b/website_bargain/static/description/assets/modules/4.jpg new file mode 100644 index 000000000..3d3da7f16 Binary files /dev/null and b/website_bargain/static/description/assets/modules/4.jpg differ diff --git a/website_bargain/static/description/assets/modules/5.jpg b/website_bargain/static/description/assets/modules/5.jpg new file mode 100644 index 000000000..0e905cf14 Binary files /dev/null and b/website_bargain/static/description/assets/modules/5.jpg differ diff --git a/website_bargain/static/description/assets/modules/6.jpg b/website_bargain/static/description/assets/modules/6.jpg new file mode 100644 index 000000000..a7a3264ef Binary files /dev/null and b/website_bargain/static/description/assets/modules/6.jpg differ diff --git a/website_bargain/static/description/assets/screenshots/1.png b/website_bargain/static/description/assets/screenshots/1.png new file mode 100644 index 000000000..01f6626b6 Binary files /dev/null and b/website_bargain/static/description/assets/screenshots/1.png differ diff --git a/website_bargain/static/description/assets/screenshots/10.png b/website_bargain/static/description/assets/screenshots/10.png new file mode 100644 index 000000000..01013cbae Binary files /dev/null and b/website_bargain/static/description/assets/screenshots/10.png differ diff --git a/website_bargain/static/description/assets/screenshots/11.png b/website_bargain/static/description/assets/screenshots/11.png new file mode 100644 index 000000000..94af3d639 Binary files /dev/null and b/website_bargain/static/description/assets/screenshots/11.png differ diff --git a/website_bargain/static/description/assets/screenshots/2.png b/website_bargain/static/description/assets/screenshots/2.png new file mode 100644 index 000000000..eecdaa04d Binary files /dev/null and b/website_bargain/static/description/assets/screenshots/2.png differ diff --git a/website_bargain/static/description/assets/screenshots/3.png b/website_bargain/static/description/assets/screenshots/3.png new file mode 100644 index 000000000..18ef4b909 Binary files /dev/null and b/website_bargain/static/description/assets/screenshots/3.png differ diff --git a/website_bargain/static/description/assets/screenshots/4.png b/website_bargain/static/description/assets/screenshots/4.png new file mode 100644 index 000000000..17e896090 Binary files /dev/null and b/website_bargain/static/description/assets/screenshots/4.png differ diff --git a/website_bargain/static/description/assets/screenshots/5.png b/website_bargain/static/description/assets/screenshots/5.png new file mode 100644 index 000000000..df53dead2 Binary files /dev/null and b/website_bargain/static/description/assets/screenshots/5.png differ diff --git a/website_bargain/static/description/assets/screenshots/6.png b/website_bargain/static/description/assets/screenshots/6.png new file mode 100644 index 000000000..e9680f742 Binary files /dev/null and b/website_bargain/static/description/assets/screenshots/6.png differ diff --git a/website_bargain/static/description/assets/screenshots/7.png b/website_bargain/static/description/assets/screenshots/7.png new file mode 100644 index 000000000..db900ad16 Binary files /dev/null and b/website_bargain/static/description/assets/screenshots/7.png differ diff --git a/website_bargain/static/description/assets/screenshots/8.png b/website_bargain/static/description/assets/screenshots/8.png new file mode 100644 index 000000000..9a1367ba1 Binary files /dev/null and b/website_bargain/static/description/assets/screenshots/8.png differ diff --git a/website_bargain/static/description/assets/screenshots/9.png b/website_bargain/static/description/assets/screenshots/9.png new file mode 100644 index 000000000..4eb85649b Binary files /dev/null and b/website_bargain/static/description/assets/screenshots/9.png differ diff --git a/website_bargain/static/description/assets/screenshots/hero-v17.gif b/website_bargain/static/description/assets/screenshots/hero-v17.gif new file mode 100644 index 000000000..fb7bf38e1 Binary files /dev/null and b/website_bargain/static/description/assets/screenshots/hero-v17.gif differ diff --git a/website_bargain/static/description/banner.jpg b/website_bargain/static/description/banner.jpg new file mode 100644 index 000000000..258db567a Binary files /dev/null and b/website_bargain/static/description/banner.jpg differ diff --git a/website_bargain/static/description/icon.png b/website_bargain/static/description/icon.png new file mode 100644 index 000000000..5e97deebe Binary files /dev/null and b/website_bargain/static/description/icon.png differ diff --git a/website_bargain/static/description/index.html b/website_bargain/static/description/index.html new file mode 100644 index 000000000..23d8a593f --- /dev/null +++ b/website_bargain/static/description/index.html @@ -0,0 +1,854 @@ + + + + + + + Odoo App 3 Index + + + + + + + + +
+
+
+
+
+ +
+
+
+ Community +
+
+ Enterprise +
+
+ Odoo.sh +
+
+
+
+
+
+

+ Product Bidding In ECommerce

+

+ Bid For Products In Odoo +

+
+ +
+
+
+
+
+

+ Key Highlights +

+
+
+
+
+
+ +
+
+

+ Timer On Product Until End Of Auction .

+
+
+
+
+
+
+ +
+
+

+ Subscription Available .

+
+
+
+
+
+
+ +
+
+

+ Different Email Notifications .

+
+
+
+
+
+
+ +
+
+

+ Option To See Bidders. +

+
+
+
+
+
+
+ +
+
+

+ Option For Buy Now . +

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

+ Auction Home Page +

+

+ Website -> Auction ->Auctions Here created auction can be seen .

+
+
+
+
+
+
+ +
+
+

+ Create a Auction and click CONFIRM

+ +
+
+
+
+
+
+ +
+
+

+ Run Auction

+

Auction will automatically start at the Start Date Time.If you want to run manually just click on RUN AUCTION Button.

+
+
+
+
+
+
+ +
+
+

+ Product in Product List + +

+

+ Customes can see AUCTION ON on that product. +

+
+
+
+
+
+
+ +
+
+

+ Product in Website.

+

+ This will be the product view in website.

+
+
+
+
+
+
+ +
+
+

+ Subscribers

+
+
+
+
+
+
+ +
+
+

+ Bidders +

+

While + Click on the Bidders.

+
+
+
+
+
+
+ +
+
+

+ This will be the bidders view in website.

+
+
+
+
+
+
+ +
+
+

+ View in backend.

+
+
+
+
+
+
+ +
+
+

+ These are different Notifications options.

+
+
+
+
+
+
+
    +
  • + Hide products price in website. +
  • +
  • + Hide add to cart button in the website. +
  • +
  • + Adds a button for price requests from merchants. +
  • +
  • + Track all requests from the backend. +
  • +
+
+
+
+
+
+
Version + 17.0.1.0.0|Released on:22nd February 2024 +
+

+ Initial Commit for Website Call For Price.

+
+
+
+
+
+
+
+

+ Related Products

+
+
+ +
+
+

+ Our Services

+ +
+
+
+
+
+
+
+
+ service-icon +
+
+

Odoo + Customization

+
+
+
+
+
+
+ service-icon +
+
+

Odoo + Implementation

+
+
+
+
+
+
+ service-icon +
+
+

Odoo + Support

+
+
+
+
+
+
+ service-icon +
+
+

Hire + Odoo Developer

+
+
+
+
+ +
+
+ service-icon +
+
+

Odoo + Integration

+
+
+
+
+
+
+ service-icon +
+
+

Odoo + Migration

+
+
+
+
+
+
+ service-icon +
+
+

Odoo + Consultancy

+
+
+
+
+
+
+ service-icon +
+
+

Odoo + Implementation

+
+
+
+
+
+
+ service-icon +
+
+

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 + 99456767686 +
+
+
+
+
+
+
+
+
+ + + + + + diff --git a/website_bargain/static/src/css/website_product_bargain.css b/website_bargain/static/src/css/website_product_bargain.css new file mode 100644 index 000000000..86817b9ff --- /dev/null +++ b/website_bargain/static/src/css/website_product_bargain.css @@ -0,0 +1,66 @@ +p { + font - size: 16 px; + line - height: 1.5; +} +#subscribe_bid { + color: #007bff; + text-decoration:none; + font-weight:bold; +} +#subscribe_bid:hover{ + cursor:pointer; + transform:scale(1.2); +} + +#bidder_information{ + width:100%; + border-collapse:collapse; +} +#bidder_information th,td{ + padding:8px; + text-align:left; + border-bottom:1px solid #ddd; +} +#bidder_information thead th{ + position:sticky; + top:0; + background-color:#f5f5f5; +} +#bidder_information tbody{ + height:200px; + overflow-y:scroll; +} +#auction_bidders{ + padding-left:60px; + color: #007bff; +} +#auction_bidders:hover{ + cursor:pointer; + transform:scale(1.2); +} +#bid_amount{ + max-width:10rem; + font-size:16px; +} +.auction_timer{ + border: 2px solid #ccc; + border-radius:6px; + padding:20px; + display: inline-block; + background:#dbdbdb4a; +} +.auction_timer:hover{ + transform:scale(1.2); +} +#timer{ + font-size: 24px; + font-weight: bold; + color: #333; + background-color: #f5f5f5; +} +.auction_min_amount{ + padding: 10px; +} +.alert { + display: none; +} diff --git a/website_bargain/static/src/js/website_bargain.js b/website_bargain/static/src/js/website_bargain.js new file mode 100644 index 000000000..9a69013b5 --- /dev/null +++ b/website_bargain/static/src/js/website_bargain.js @@ -0,0 +1,270 @@ +/** @odoo-module **/ +import { WebsiteSale } from '@website_sale/js/website_sale'; +import { jsonrpc } from "@web/core/network/rpc_service"; + +/**This is a JavaScript code written for the Odoo e-commerce platform. +It extends the functionality of the WebsiteSale module by adding an auction +feature, allowing customers to bid on products, and setting up a timer to track +the duration of the auction.**/ +WebsiteSale.include({ + /**The start function initializes the auction timer when the page is loaded. + It first checks if there are any ongoing auctions and hides the + "add to cart" button if the product is being auctioned. Then, it retrieves + the product and auction IDs from the input fields, sends an AJAX request to + the server to fetch the auction details, and calculates the time remaining + until the auction ends. If the auction has ended, the function redirects + the user to the shop page, and if not, it sets up an interval to update + the timer every second.**/ + start: function() { + /** function to add timer and check the time **/ + this._super(...arguments); + var modal_title = this.$('#modal_title')[0] + var modal_message = this.$('#modal_message')[0] + var product_name = this.$('input[name="auction_product_id"]').val(); + var auction_id_status = this.$('input[name="auction_id"]').val() + var bellIcon = this.el.querySelector('#subscribe_bid'); + if (auction_id_status != undefined){ + jsonrpc('/subscribe/status', { + 'auction_id': auction_id_status, + }).then((data) => { + if (data){ + bellIcon.style.color = 'red' + bellIcon.classList.remove('fa-bell-o') + bellIcon.classList.add('fa-bell') + bellIcon.innerHTML = 'Unsubscribe' + } + else { + bellIcon.style.color = '#007bff' + bellIcon.classList.remove('fa-bell') + bellIcon.classList.add('fa-bell-o') + bellIcon.innerHTML = 'Subscribe' + } + }) + } + let auctionText = this.$('#modal_message')[0] + if (auctionText) { + $.each($('.o_wsale_product_btn'), (key, values) => { + if (values.nextElementSibling.innerHTML == 'AUCTION ON') { + values.style.display = "none" + } + }) + } + let product_id = this.$('input[name="auction_product_id"]').val(); + let auction_id = this.$('input[name="auction_id"]').val(); + let timerId; // variable to hold the ID of the interval timer + if (product_id) { + let product_product_id = this.$('input[name="product_product_id"]').val() + jsonrpc('/auction/timer', { + 'product_id': product_id, + 'auction_id': auction_id + }).then((data) => { + if (new Date() > new Date(data['end_time'])) { + if (data['extend_time']) { + if (new Date() > new Date(data['extend_time'])) { + jsonrpc('/auction/close', { + 'product_id': product_id, + 'auction_id': auction_id + }).then(() => { + jsonrpc('/shop/sale/order', { + 'product_product_id': product_product_id, + 'product_id': product_id, + 'auction_id': auction_id + }) + }) + window.location.href = '/shop' + } + } else { + jsonrpc('/auction/close', { + 'product_id': product_id, + 'auction_id': auction_id + }).then(() => { + jsonrpc('/shop/sale/order', { + 'product_product_id': product_product_id, + 'product_id': product_id, + 'auction_id': auction_id + }) + }) + window.location.href = '/shop' + } + } else { + var self = this; + timerId = setInterval(function() { + var time_key = data['extend_time'] ? 'extend_time' : 'end_time' + var time_remaining = new Date(data[time_key]) - new Date() + var days = Math.floor(time_remaining / (1000 * 60 * 60 * 24)); + var hours = Math.floor((time_remaining / (1000 * 60 * 60)) % 24); + var minutes = Math.floor((time_remaining / (1000 * 60)) % 60); + var seconds = Math.floor((time_remaining / 1000) % 60); + if (self.el.querySelector('#timer')) { + self.el.querySelector('#timer').innerHTML = days + "d." + " " + hours + "h." + " " + minutes + "m." + " " + seconds + "s." + } + if (time_remaining <= 0) { + clearInterval(timerId); + } + }, 1000); + var time_key = data['extend_time'] ? 'extend_time' : 'end_time' + var time_remaining = new Date(data[time_key]) - new Date() + if (time_remaining <= 0) { + window.location.href = '/shop'; + } + } + }) + } + }, + events: { + /** Click event for subscribe button**/ + 'click #subscribe_bid': '_clickSubscribe', + + /**Click event for add to cart and buy now buttons**/ + 'click #add_to_cart, .o_we_buy_now, #products_grid .o_wsale_product_btn .a-submit': 'async _onClickAdd', + + /**Click event for place bid button**/ + 'click #place_bid_button': '_placeBid', + + /**Click event for hide modal button**/ + 'click #hide_modal': '_hideModal', + + /**Click event for buy now button**/ + 'click .js_add_cart': '_buyNow' + }, + /** Function to hide auction messages after 5 seconds **/ + timeout: function() { + var self = this; + setTimeout(function() { + self.el.querySelector('#auction_messages').style.display = "none" + }, 5000) + }, + /** Function to handle subscription to auction updates **/ + _clickSubscribe: function() { + // Get product and auction IDs + let product_id = this.$('input[name="auction_product_id"]').val() + let auction_id = this.$('input[name="auction_id"]').val(); + + // Get subscribe button and auction messages elements + var bellIcon = this.el.querySelector('#subscribe_bid'); + var messages = this.el.querySelector('#auction_messages') + + // If button says "Subscribe", subscribe user to auction updates + if (bellIcon.innerHTML == 'Subscribe' ) { + bellIcon.style.color = 'red' + bellIcon.classList.remove('fa-bell-o') + bellIcon.classList.add('fa-bell') + bellIcon.innerHTML = 'Unsubscribe' + jsonrpc('/subscribe/bid', { + 'text': 'subscribe', + 'product_id': product_id, + 'auction_id': auction_id + }).then((data) => { + messages.innerHTML = data + messages.classList.remove('alert-warning') + messages.classList.add('alert-success') + messages.style.display = "block" + this.timeout() + }) + } + /** Otherwise, unsubscribe user from auction updates **/ + else { + bellIcon.style.color = '#007bff' + bellIcon.classList.remove('fa-bell') + bellIcon.classList.add('fa-bell-o') + bellIcon.innerHTML = 'Subscribe' + jsonrpc('/subscribe/bid', { + 'text': 'unsubscribe', + 'auction_id': auction_id + }).then((data) => { + messages.classList.add('alert-warning') + messages.innerHTML = data + messages.style.display = "block" + this.timeout() + }) + } + }, + /** Function to handle adding products to cart **/ + _onClickAdd: function(ev) { + ev.preventDefault(); + var def = () => { + this.getCartHandlerOptions(ev); + return this._handleAdd($(ev.currentTarget).closest('form')); + }; + if ($('.js_add_cart_variants').children().length) { + return this._getCombinationInfo(ev).then(() => { + return !$(ev.target).closest('.js_product').hasClass("css_not_available") ? def() : Promise.resolve(); + }); + } + return def(); + }, + /** Function to submit form when adding products to cart **/ + _submitForm: function() { + const params = this.rootProduct; + const $product = $('#product_detail'); + const productTrackingInfo = $product.data('product-tracking-info'); + if (productTrackingInfo) { + productTrackingInfo.quantity = params.quantity; + $product.trigger('add_to_cart_event', [productTrackingInfo]); + } + params.add_qty = params.quantity; + params.product_custom_attribute_values = JSON.stringify(params.product_custom_attribute_values); + params.no_variant_attribute_values = JSON.stringify(params.no_variant_attribute_values); + delete params.quantity; + return this.addToCart(params); + }, + _placeBid: function() { + /** Function to place a bid + Get the bid amount and minimum amount from the page **/ + var bid_amount = parseFloat(this.$('input[id="bid_amount"]').val()) + var min_amount = parseFloat(this.$('#min_amount')[0].innerHTML) + let product_id = this.$('input[name="auction_product_id"]').val() + let auction_id = this.$('input[name="auction_id"]').val(); + var messages = this.$('#auction_messages')[0] + if (min_amount >= bid_amount) { + modal_title.innerHTML = "Warning!" + modal_message.innerHTML = "Please check the minimum bid amount" + this.$('#modal_product_warning').modal('show') + } else { + jsonrpc('/place_bid', { + 'bid_amount': bid_amount, + 'product_id': product_id, + 'auction_id': auction_id + }).then((data) => { + if (data){ + messages.innerHTML = data['bid_placed'] + messages.style.display = "block"; + this.timeout() + window.location.reload() + } + else { + modal_title.innerHTML = "Same amount placed" + modal_message.innerHTML = "You have already placed this amount. Please reconsider your bid amount" + this.$('#modal_product_warning').modal('show') + } + }) + } + }, + /**Click event for hide modal button**/ + _hideModal: function() { + this.$('#modal_product_warning').modal('hide') + }, + _buyNow: function() { + /** function for buy now button **/ + let product_id = this.$('input[name="auction_product_id"]').val() + let product_template_id = this.$('input[name="product_product_id"]').val() + let auction_id = this.$('input[name="auction_id"]').val(); + jsonrpc('/buy/now', { + product_id: parseInt(product_template_id), + 'product_id': product_template_id, + 'auction_id': auction_id, + 'auction_product_id': product_id, + 'add_qty': 1 + }).then(function(data) {}) + jsonrpc('/auction/close', { + 'product_id': product_id, + 'auction_id': auction_id, + }) + modal_title.innerHTML = "Success" + modal_message.innerHTML = "You will get a email please confirm and pay now you will be redirected to home page" + $('#modal_product_warning').modal('show') + setTimeout(function() { + window.location.href = '/shop' + }, 5000) + }, +}) diff --git a/website_bargain/views/bargain_information_views.xml b/website_bargain/views/bargain_information_views.xml new file mode 100644 index 000000000..e7f0b16d7 --- /dev/null +++ b/website_bargain/views/bargain_information_views.xml @@ -0,0 +1,51 @@ + + + + + bargain.information.view.form + bargain.information + +
+ + + + + + + + + + + + + + +
+ + + +
+
+
+
+ + + bargain.information.view.tree + bargain.information + + + + + + + + + + + Bidder Information + bargain.information + tree,form,activity + +
diff --git a/website_bargain/views/bargain_subscribers_views.xml b/website_bargain/views/bargain_subscribers_views.xml new file mode 100644 index 000000000..68f45076b --- /dev/null +++ b/website_bargain/views/bargain_subscribers_views.xml @@ -0,0 +1,53 @@ + + + + + bargain.subscribers.view.form + bargain.subscribers + +
+ + + + + + + + + + + + + + + +
+ + + +
+
+
+
+ + + bargain.subscribers.view.tree + bargain.subscribers + + + + + + + + + + + + + Bargain Subscribers + bargain.subscribers + tree,form + +
diff --git a/website_bargain/views/bargain_template_views.xml b/website_bargain/views/bargain_template_views.xml new file mode 100644 index 000000000..985308fe4 --- /dev/null +++ b/website_bargain/views/bargain_template_views.xml @@ -0,0 +1,31 @@ + + + + + bargain.template.view.form + bargain.template + +
+ + + + + + + +
+ + + +
+
+
+
+ + + Website Bidding Template + bargain.template + tree,form + +
diff --git a/website_bargain/views/bidders_information_templates.xml b/website_bargain/views/bidders_information_templates.xml new file mode 100644 index 000000000..f30406113 --- /dev/null +++ b/website_bargain/views/bidders_information_templates.xml @@ -0,0 +1,64 @@ + + + + diff --git a/website_bargain/views/product_template_views.xml b/website_bargain/views/product_template_views.xml new file mode 100644 index 000000000..4489289b8 --- /dev/null +++ b/website_bargain/views/product_template_views.xml @@ -0,0 +1,17 @@ + + + + + product.template.view.form.inherit.website.bargain + + product.template + + + + + + + + diff --git a/website_bargain/views/website_bargain_menus.xml b/website_bargain/views/website_bargain_menus.xml new file mode 100644 index 000000000..c9ba0e61b --- /dev/null +++ b/website_bargain/views/website_bargain_menus.xml @@ -0,0 +1,27 @@ + + + + + + + + diff --git a/website_bargain/views/website_bargain_views.xml b/website_bargain/views/website_bargain_views.xml new file mode 100644 index 000000000..9222bc395 --- /dev/null +++ b/website_bargain/views/website_bargain_views.xml @@ -0,0 +1,158 @@ + + + + + website.bargain.view.form + website.bargain + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+

Bidder Information

+
+ +
+ +
+

Subscribers

+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + + +
+
+
+
+ + + website.bargain.view.tree + website.bargain + + + + + + + + + + + + + + Website Bargain + website.bargain + tree,form + +
diff --git a/website_bargain/views/website_product_views_templates.xml b/website_bargain/views/website_product_views_templates.xml new file mode 100644 index 000000000..537ef2616 --- /dev/null +++ b/website_bargain/views/website_product_views_templates.xml @@ -0,0 +1,241 @@ + + + + diff --git a/website_bargain/views/website_shop_auction_templates.xml b/website_bargain/views/website_shop_auction_templates.xml new file mode 100644 index 000000000..635bdbfd6 --- /dev/null +++ b/website_bargain/views/website_shop_auction_templates.xml @@ -0,0 +1,40 @@ + + + + +