diff --git a/website_bargain/README.rst b/website_bargain/README.rst new file mode 100644 index 000000000..381b23825 --- /dev/null +++ b/website_bargain/README.rst @@ -0,0 +1,46 @@ +.. 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, + (V15) Safa Faheem PE +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..399f2a801 --- /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: Cybrosys Techno Solutions() +# +# 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..64b07eeee --- /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: Cybrosys Techno Solutions() +# +# 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': '15.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.png'], + '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..0c7cceeae --- /dev/null +++ b/website_bargain/controllers/website_bargain.py @@ -0,0 +1,352 @@ +# -*- coding: utf-8 -*- +############################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies() +# Author: Cybrosys Techno Solutions() +# +# 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([]) + 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 the 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..b76f2096e --- /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..7c0b38e02 --- /dev/null +++ b/website_bargain/doc/RELEASE_NOTES.md @@ -0,0 +1,7 @@ +## Module + +#### 19.09.2024 +#### Version 15.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..d428337fa --- /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: Cybrosys Techno Solutions() +# +# 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..6f056a10f --- /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: Cybrosys Techno Solutions() +# +# 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..eae92d3bb --- /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: Cybrosys Techno Solutions() +# +# 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..dad0be922 --- /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: Cybrosys Techno Solutions() +# +# 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..e5f121b92 --- /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: Cybrosys Techno Solutions() +# +# 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..4b549a672 --- /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: Cybrosys Techno Solutions() +# +# 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=lambda self: fields.datetime.now(), + 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.now(): + # Set the product as an auction and update the website + auction.product_id.is_auction = True + auction.product_id.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/chatter_view.jpg b/website_bargain/static/description/assets/modules/chatter_view.jpg new file mode 100644 index 000000000..8890ee31d Binary files /dev/null and b/website_bargain/static/description/assets/modules/chatter_view.jpg differ diff --git a/website_bargain/static/description/assets/modules/dynamic_financial_reports.png b/website_bargain/static/description/assets/modules/dynamic_financial_reports.png new file mode 100644 index 000000000..5238bdeab Binary files /dev/null and b/website_bargain/static/description/assets/modules/dynamic_financial_reports.png differ diff --git a/website_bargain/static/description/assets/modules/hid_menu.png b/website_bargain/static/description/assets/modules/hid_menu.png new file mode 100644 index 000000000..6bc155887 Binary files /dev/null and b/website_bargain/static/description/assets/modules/hid_menu.png differ diff --git a/website_bargain/static/description/assets/modules/login_style.png b/website_bargain/static/description/assets/modules/login_style.png new file mode 100644 index 000000000..e20126a45 Binary files /dev/null and b/website_bargain/static/description/assets/modules/login_style.png differ diff --git a/website_bargain/static/description/assets/modules/login_user.png b/website_bargain/static/description/assets/modules/login_user.png new file mode 100644 index 000000000..4fbe85ac1 Binary files /dev/null and b/website_bargain/static/description/assets/modules/login_user.png differ diff --git a/website_bargain/static/description/assets/modules/qr_code.png b/website_bargain/static/description/assets/modules/qr_code.png new file mode 100644 index 000000000..6bc155887 Binary files /dev/null and b/website_bargain/static/description/assets/modules/qr_code.png differ diff --git a/website_bargain/static/description/assets/screenshots/hero.gif b/website_bargain/static/description/assets/screenshots/hero.gif new file mode 100644 index 000000000..ad1110cda Binary files /dev/null and b/website_bargain/static/description/assets/screenshots/hero.gif differ diff --git a/website_bargain/static/description/assets/screenshots/website_bargain_01.png b/website_bargain/static/description/assets/screenshots/website_bargain_01.png new file mode 100644 index 000000000..715006681 Binary files /dev/null and b/website_bargain/static/description/assets/screenshots/website_bargain_01.png differ diff --git a/website_bargain/static/description/assets/screenshots/website_bargain_02.png b/website_bargain/static/description/assets/screenshots/website_bargain_02.png new file mode 100644 index 000000000..6a2c14f81 Binary files /dev/null and b/website_bargain/static/description/assets/screenshots/website_bargain_02.png differ diff --git a/website_bargain/static/description/assets/screenshots/website_bargain_03.png b/website_bargain/static/description/assets/screenshots/website_bargain_03.png new file mode 100644 index 000000000..89bb77e76 Binary files /dev/null and b/website_bargain/static/description/assets/screenshots/website_bargain_03.png differ diff --git a/website_bargain/static/description/assets/screenshots/website_bargain_04.png b/website_bargain/static/description/assets/screenshots/website_bargain_04.png new file mode 100644 index 000000000..74fd02070 Binary files /dev/null and b/website_bargain/static/description/assets/screenshots/website_bargain_04.png differ diff --git a/website_bargain/static/description/assets/screenshots/website_bargain_05.png b/website_bargain/static/description/assets/screenshots/website_bargain_05.png new file mode 100644 index 000000000..b7cd592b1 Binary files /dev/null and b/website_bargain/static/description/assets/screenshots/website_bargain_05.png differ diff --git a/website_bargain/static/description/assets/screenshots/website_bargain_06.png b/website_bargain/static/description/assets/screenshots/website_bargain_06.png new file mode 100644 index 000000000..d78c6ee12 Binary files /dev/null and b/website_bargain/static/description/assets/screenshots/website_bargain_06.png differ diff --git a/website_bargain/static/description/assets/screenshots/website_bargain_07.png b/website_bargain/static/description/assets/screenshots/website_bargain_07.png new file mode 100644 index 000000000..a50d14466 Binary files /dev/null and b/website_bargain/static/description/assets/screenshots/website_bargain_07.png differ diff --git a/website_bargain/static/description/assets/screenshots/website_bargain_08.png b/website_bargain/static/description/assets/screenshots/website_bargain_08.png new file mode 100644 index 000000000..dc4fa1072 Binary files /dev/null and b/website_bargain/static/description/assets/screenshots/website_bargain_08.png differ diff --git a/website_bargain/static/description/assets/screenshots/website_bargain_09.png b/website_bargain/static/description/assets/screenshots/website_bargain_09.png new file mode 100644 index 000000000..df62eab4f Binary files /dev/null and b/website_bargain/static/description/assets/screenshots/website_bargain_09.png differ diff --git a/website_bargain/static/description/assets/screenshots/website_bargain_10.png b/website_bargain/static/description/assets/screenshots/website_bargain_10.png new file mode 100644 index 000000000..d308f3152 Binary files /dev/null and b/website_bargain/static/description/assets/screenshots/website_bargain_10.png differ diff --git a/website_bargain/static/description/banner.png b/website_bargain/static/description/banner.png new file mode 100644 index 000000000..40d5ac46f Binary files /dev/null and b/website_bargain/static/description/banner.png differ diff --git a/website_bargain/static/description/icon.png b/website_bargain/static/description/icon.png new file mode 100644 index 000000000..ac6c5c744 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..4bf7c67b4 --- /dev/null +++ b/website_bargain/static/description/index.html @@ -0,0 +1,593 @@ +
+ +
+ +
+
+ Community +
+
+ Enterprise +
+
+
+ +
+
+
+ +

+ Product Bidding In ECommerce

+

+ Bid For Products In Odoo +

+ + +
+
+
+
+ +
+ x +
+ +
+

+ Explore This Module

+
+ + + +
+
+ +
+

+ Overview

+
+
+
+ This module provides a bidding system where customers can place their bids on products, and the highest bidder wins the auction. This module integrates seamlessly with the website sale module of Odoo, and it is highly configurable to meet the specific needs of each business. Additionally, it provides several features such as starting and ending dates for auctions, buy now option, and real-time updates for bids. +
+
+ + +
+
+ +
+

+ Features

+
+
+
+
+ + Timer On Product Until End Of Auction. +
+
+
+
+ + Subscription Available. +
+
+
+
+ + Different Email Notifications. +
+
+
+
+ + Option To See Bidders. +
+
+
+
+ + Option For Buy Now. +
+
+
+ + +
+
+ +
+

+ Screenshots

+
+
+
+
+

+ Auction Home Page

+

Navigate to 'Auction' menu in Website to create new auctions.

+ +
+
+

+ Create an auction by entering the details and then click 'CONFIRM'.

+ +
+
+

+ Run Auction

+

+ Auction will automatically start at the Start Date Time if it is in confirmed stage.If you want to run manually just click on RUN AUCTION Button.

+ +
+
+

+ 'Auction On' in Shop Page.

+

+ Customers can see 'AUCTION ON' on that product in the shop page.

+ +
+
+

+ Product in Website

+

+ This will be the product view in website.

+ +
+
+

+ Subscribers

+ +
+
+

+ Bidders

+

+ This will be the bidders view in website.

+ + +
+
+

+ View in backend. +

+ +
+
+

+ These are different Notifications options.

+ +
+
+
+ + +
+
+

Suggested Products

+
+ +
+
+ + +
+
+ +
+

+ Our Services

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

+ Our Industries

+
+
+
+
+
+ +
+ Trading
+

+ Easily procure and sell your products

+
+
+
+
+ +
+ POS
+

+ Easy configuration and convivial experience

+
+
+
+
+ +
+ Education
+

+ A platform for educational management

+
+
+
+
+ +
+ Manufacturing
+

+ Plan, track and schedule your operations

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

+ Mobile friendly, awe-inspiring product pages

+
+
+
+
+ +
+ Service Management
+

+ Keep track of services and invoice

+
+
+
+
+ +
+ Restaurant
+

+ Run your bar or restaurant methodically

+
+
+
+
+ +
+ Hotel Management
+

+ An all-inclusive hotel management application

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

+ Support

+
+
+
+
+
+
+ +
+
+

Need Help?

+

Got questions or need help? + Get in touch.

+ +

+ odoo@cybrosys.com

+
+
+
+
+
+
+
+ +
+
+

WhatsApp

+

Say hi to us on WhatsApp!

+ +

+ +91 86068 27707

+
+
+
+
+
+
+
+ +
+
+
+ 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..511f464a6 --- /dev/null +++ b/website_bargain/static/src/js/website_bargain.js @@ -0,0 +1,270 @@ +/** @odoo-module **/ +var website_sale_inherit = require('website_sale.website_sale'); +var ajax = require('web.ajax'); + +/**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.**/ +website_sale_inherit.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){ + ajax.jsonRpc('/subscribe/status', 'call', { + '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() + ajax.jsonRpc('/auction/timer', 'call', { + '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'])) { + ajax.jsonRpc('/auction/close', 'call', { + 'product_id': product_id, + 'auction_id': auction_id + }).then(() => { + ajax.jsonRpc('/shop/sale/order', 'call', { + 'product_product_id': product_product_id, + 'product_id': product_id, + 'auction_id': auction_id + }) + }) + window.location.href = '/shop' + } + } else { + ajax.jsonRpc('/auction/close', 'call', { + 'product_id': product_id, + 'auction_id': auction_id + }).then(() => { + ajax.jsonRpc('/shop/sale/order', 'call', { + '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' + ajax.jsonRpc('/subscribe/bid', 'call', { + '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' + ajax.jsonRpc('/subscribe/bid', 'call',{ + '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 { + ajax.jsonRpc('/place_bid', 'call', { + '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(); + ajax.jsonRpc('/buy/now', 'call',{ + 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) {}) + ajax.jsonRpc('/auction/close', 'call',{ + '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..7c602c317 --- /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..1e9eed0c5 --- /dev/null +++ b/website_bargain/views/website_product_views_templates.xml @@ -0,0 +1,187 @@ + + + + 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..1fad5cd1f --- /dev/null +++ b/website_bargain/views/website_shop_auction_templates.xml @@ -0,0 +1,22 @@ + + + + +