From 3751379f1e9a4c215fb6eb898b4ccc67659b9ace Mon Sep 17 00:00:00 2001 From: stephanchrst Date: Tue, 10 May 2022 21:51:50 +0700 Subject: initial commit 2 --- addons/website_event_sale/models/__init__.py | 6 + addons/website_event_sale/models/product.py | 10 ++ .../website_event_sale/models/product_pricelist.py | 23 ++++ addons/website_event_sale/models/sale_order.py | 121 +++++++++++++++++++++ addons/website_event_sale/models/website.py | 11 ++ 5 files changed, 171 insertions(+) create mode 100644 addons/website_event_sale/models/__init__.py create mode 100644 addons/website_event_sale/models/product.py create mode 100644 addons/website_event_sale/models/product_pricelist.py create mode 100644 addons/website_event_sale/models/sale_order.py create mode 100644 addons/website_event_sale/models/website.py (limited to 'addons/website_event_sale/models') diff --git a/addons/website_event_sale/models/__init__.py b/addons/website_event_sale/models/__init__.py new file mode 100644 index 00000000..a9c94cbe --- /dev/null +++ b/addons/website_event_sale/models/__init__.py @@ -0,0 +1,6 @@ +# -*- coding: utf-8 -*- + +from . import product +from . import product_pricelist +from . import sale_order +from . import website diff --git a/addons/website_event_sale/models/product.py b/addons/website_event_sale/models/product.py new file mode 100644 index 00000000..27a2f78e --- /dev/null +++ b/addons/website_event_sale/models/product.py @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- + +from odoo import fields, models + + +# defined for access rules +class Product(models.Model): + _inherit = 'product.product' + + event_ticket_ids = fields.One2many('event.event.ticket', 'product_id', string='Event Tickets') diff --git a/addons/website_event_sale/models/product_pricelist.py b/addons/website_event_sale/models/product_pricelist.py new file mode 100644 index 00000000..5b0d4465 --- /dev/null +++ b/addons/website_event_sale/models/product_pricelist.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- + +from odoo import _, api, models + +class PricelistItem(models.Model): + _inherit = "product.pricelist.item" + + @api.onchange('applied_on', 'product_id', 'product_tmpl_id', 'min_quantity') + def _onchange_event_sale_warning(self): + if self.min_quantity > 0: + msg = '' + if self.applied_on == '3_global' or self.applied_on == '2_product_category': + msg = _("A pricelist item with a positive min. quantity will not be applied to the event tickets products.") + elif ((self.applied_on == '1_product' and self.product_tmpl_id.event_ok) or + (self.applied_on == '0_product_variant' and self.product_id.event_ok)): + msg = _("A pricelist item with a positive min. quantity cannot be applied to this event tickets product.") + if msg: + return {'warning': + { + 'title': _("Warning"), + 'message': msg + } + } diff --git a/addons/website_event_sale/models/sale_order.py b/addons/website_event_sale/models/sale_order.py new file mode 100644 index 00000000..296738c6 --- /dev/null +++ b/addons/website_event_sale/models/sale_order.py @@ -0,0 +1,121 @@ +# -*- coding: utf-8 -*- + +from odoo import api, models, _ +from odoo.exceptions import UserError + + +class SaleOrder(models.Model): + _inherit = "sale.order" + + def _cart_find_product_line(self, product_id=None, line_id=None, **kwargs): + self.ensure_one() + lines = super(SaleOrder, self)._cart_find_product_line(product_id, line_id) + if line_id: + return lines + domain = [('id', 'in', lines.ids)] + if self.env.context.get("event_ticket_id"): + domain.append(('event_ticket_id', '=', self.env.context.get("event_ticket_id"))) + return self.env['sale.order.line'].sudo().search(domain) + + def _website_product_id_change(self, order_id, product_id, qty=0): + order = self.env['sale.order'].sudo().browse(order_id) + if self._context.get('pricelist') != order.pricelist_id.id: + self = self.with_context(pricelist=order.pricelist_id.id) + + values = super(SaleOrder, self)._website_product_id_change(order_id, product_id, qty=qty) + event_ticket_id = None + if self.env.context.get("event_ticket_id"): + event_ticket_id = self.env.context.get("event_ticket_id") + else: + product = self.env['product.product'].browse(product_id) + if product.event_ticket_ids: + event_ticket_id = product.event_ticket_ids[0].id + + if event_ticket_id: + ticket = self.env['event.event.ticket'].browse(event_ticket_id) + if product_id != ticket.product_id.id: + raise UserError(_("The ticket doesn't match with this product.")) + + values['product_id'] = ticket.product_id.id + values['event_id'] = ticket.event_id.id + values['event_ticket_id'] = ticket.id + if order.pricelist_id.discount_policy == 'without_discount': + values['price_unit'] = ticket.price + else: + values['price_unit'] = ticket.price_reduce + values['name'] = ticket._get_ticket_multiline_description() + + # avoid writing related values that end up locking the product record + values.pop('event_ok', None) + + return values + + def _cart_update(self, product_id=None, line_id=None, add_qty=0, set_qty=0, **kwargs): + OrderLine = self.env['sale.order.line'] + + try: + if add_qty: + add_qty = float(add_qty) + except ValueError: + add_qty = 1 + try: + if set_qty: + set_qty = float(set_qty) + except ValueError: + set_qty = 0 + + if line_id: + line = OrderLine.browse(line_id) + ticket = line.event_ticket_id + old_qty = int(line.product_uom_qty) + if ticket.id: + self = self.with_context(event_ticket_id=ticket.id, fixed_price=1) + else: + line = None + ticket = self.env['event.event.ticket'].search([('product_id', '=', product_id)], limit=1) + old_qty = 0 + new_qty = set_qty if set_qty else (add_qty or 0 + old_qty) + + # case: buying tickets for a sold out ticket + values = {} + if ticket and ticket.seats_limited and ticket.seats_available <= 0: + values['warning'] = _('Sorry, The %(ticket)s tickets for the %(event)s event are sold out.') % { + 'ticket': ticket.name, + 'event': ticket.event_id.name} + new_qty, set_qty, add_qty = 0, 0, -old_qty + # case: buying tickets, too much attendees + elif ticket and ticket.seats_limited and new_qty > ticket.seats_available: + values['warning'] = _('Sorry, only %(remaining_seats)d seats are still available for the %(ticket)s ticket for the %(event)s event.') % { + 'remaining_seats': ticket.seats_available, + 'ticket': ticket.name, + 'event': ticket.event_id.name} + new_qty, set_qty, add_qty = ticket.seats_available, ticket.seats_available, 0 + values.update(super(SaleOrder, self)._cart_update(product_id, line_id, add_qty, set_qty, **kwargs)) + + # removing attendees + if ticket and new_qty < old_qty: + attendees = self.env['event.registration'].search([ + ('state', '!=', 'cancel'), + ('sale_order_id', 'in', self.ids), # To avoid break on multi record set + ('event_ticket_id', '=', ticket.id), + ], offset=new_qty, limit=(old_qty - new_qty), order='create_date asc') + attendees.action_cancel() + # adding attendees + elif ticket and new_qty > old_qty: + # do not do anything, attendees will be created at SO confirmation if not given previously + pass + return values + + +class SaleOrderLine(models.Model): + _inherit = "sale.order.line" + + @api.depends('product_id.display_name', 'event_ticket_id.display_name') + def _compute_name_short(self): + """ If the sale order line concerns a ticket, we don't want the product name, but the ticket name instead. + """ + super(SaleOrderLine, self)._compute_name_short() + + for record in self: + if record.event_ticket_id: + record.name_short = record.event_ticket_id.display_name diff --git a/addons/website_event_sale/models/website.py b/addons/website_event_sale/models/website.py new file mode 100644 index 00000000..d1bf0a4f --- /dev/null +++ b/addons/website_event_sale/models/website.py @@ -0,0 +1,11 @@ +# -*- coding: utf-8 -*- + +from odoo import models + + +class Website(models.Model): + _inherit = 'website' + + def sale_product_domain(self): + # remove product event from the website content grid and list view (not removed in detail view) + return ['&'] + super(Website, self).sale_product_domain() + [('event_ok', '=', False)] -- cgit v1.2.3