mirror of
https://github.com/bringout/oca-ocb-sale.git
synced 2026-04-27 12:52:07 +02:00
19.0 vanilla
This commit is contained in:
parent
79f83631d5
commit
73afc09215
6267 changed files with 1534193 additions and 1130106 deletions
|
|
@ -1,6 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
from . import product
|
||||
from . import product_pricelist
|
||||
from . import sale_order
|
||||
from . import website
|
||||
from . import sale_order_line
|
||||
|
|
|
|||
|
|
@ -1,19 +1,36 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
# defined for access rules
|
||||
class Product(models.Model):
|
||||
class ProductProduct(models.Model):
|
||||
_inherit = 'product.product'
|
||||
|
||||
event_ticket_ids = fields.One2many('event.event.ticket', 'product_id', string='Event Tickets')
|
||||
|
||||
def _is_add_to_cart_allowed(self):
|
||||
# Allow adding event tickets to the cart regardless of product's rules
|
||||
self.ensure_one()
|
||||
res = super()._is_add_to_cart_allowed()
|
||||
return res or any(event.website_published for event in self.event_ticket_ids.event_id)
|
||||
def _can_return_content(self, field_name=None, access_token=None):
|
||||
""" Override of `orm` to give public users access to the unpublished product image.
|
||||
|
||||
Give access to the public users to the unpublished product images if they are linked to an
|
||||
event ticket.
|
||||
|
||||
:param field_name: The name of the field to check.
|
||||
:param access_token: The access token.
|
||||
:return: Whether to allow the access to the image.
|
||||
:rtype: bool
|
||||
"""
|
||||
if (
|
||||
field_name in ["image_%s" % size for size in [1920, 1024, 512, 256, 128]]
|
||||
and self.sudo().event_ticket_ids
|
||||
):
|
||||
return True
|
||||
return super()._can_return_content(field_name, access_token)
|
||||
|
||||
def _get_product_placeholder_filename(self):
|
||||
if self.event_ticket_ids:
|
||||
return 'website_event_sale/static/img/event_ticket_placeholder_thumbnail.png'
|
||||
return super()._get_product_placeholder_filename()
|
||||
|
||||
class ProductTemplate(models.Model):
|
||||
_inherit = 'product.template'
|
||||
|
|
|
|||
|
|
@ -2,7 +2,8 @@
|
|||
|
||||
from odoo import _, api, models
|
||||
|
||||
class PricelistItem(models.Model):
|
||||
|
||||
class ProductPricelistItem(models.Model):
|
||||
_inherit = "product.pricelist.item"
|
||||
|
||||
@api.onchange('applied_on', 'product_id', 'product_tmpl_id', 'min_quantity')
|
||||
|
|
@ -11,8 +12,8 @@ class PricelistItem(models.Model):
|
|||
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.detailed_type == 'event') or
|
||||
(self.applied_on == '0_product_variant' and self.product_id.detailed_type == 'event')):
|
||||
elif ((self.applied_on == '1_product' and self.product_tmpl_id.service_tracking == 'event') or
|
||||
(self.applied_on == '0_product_variant' and self.product_id.service_tracking == 'event')):
|
||||
msg = _("A pricelist item with a positive min. quantity cannot be applied to this event tickets product.")
|
||||
if msg:
|
||||
return {'warning':
|
||||
|
|
|
|||
|
|
@ -1,24 +1,34 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import api, models, _
|
||||
from odoo import _, 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, event_ticket_id=False, **kwargs):
|
||||
lines = super()._cart_find_product_line(product_id, line_id, **kwargs)
|
||||
if line_id or not event_ticket_id:
|
||||
def _cart_find_product_line(self, *args, event_slot_id=False, event_ticket_id=False, **kwargs):
|
||||
lines = super()._cart_find_product_line(
|
||||
*args, event_slot_id=event_slot_id, event_ticket_id=event_ticket_id, **kwargs,
|
||||
)
|
||||
if not event_slot_id and not event_ticket_id:
|
||||
return lines
|
||||
|
||||
return lines.filtered(
|
||||
lambda line: line.event_ticket_id.id == event_ticket_id
|
||||
)
|
||||
return lines.filtered(lambda line: line.event_slot_id.id == event_slot_id and line.event_ticket_id.id == event_ticket_id)
|
||||
|
||||
def _verify_updated_quantity(self, order_line, product_id, new_qty, event_ticket_id=False, **kwargs):
|
||||
def _verify_updated_quantity(
|
||||
self, order_line, product_id, new_qty, uom_id, *, event_slot_id=False, event_ticket_id=False, **kwargs
|
||||
):
|
||||
"""Restrict quantity updates for event tickets according to available seats."""
|
||||
new_qty, warning = super()._verify_updated_quantity(order_line, product_id, new_qty, **kwargs)
|
||||
new_qty, warning = super()._verify_updated_quantity(
|
||||
order_line,
|
||||
product_id,
|
||||
new_qty,
|
||||
uom_id,
|
||||
event_slot_id=event_slot_id,
|
||||
event_ticket_id=event_ticket_id,
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
if not event_ticket_id:
|
||||
if not order_line.event_ticket_id or new_qty < order_line.product_uom_qty:
|
||||
|
|
@ -30,6 +40,9 @@ class SaleOrder(models.Model):
|
|||
ticket = self.env['event.event.ticket'].browse(event_ticket_id).exists()
|
||||
if not ticket:
|
||||
raise UserError(_("The provided ticket doesn't exist"))
|
||||
slot = self.env['event.slot'].browse(event_slot_id).exists()
|
||||
if event_slot_id and not slot:
|
||||
raise UserError(_("The provided ticket slot doesn't exist"))
|
||||
|
||||
# TODO TDE consider full cart qty and not only added qty
|
||||
# if event seats are not auto confirmed.
|
||||
|
|
@ -39,7 +52,8 @@ class SaleOrder(models.Model):
|
|||
existing_qty = order_line.product_uom_qty if order_line else 0
|
||||
qty_added = new_qty - existing_qty
|
||||
warning = ''
|
||||
if ticket.seats_limited and ticket.seats_available <= 0:
|
||||
ticket_seats_available = ticket.event_id._get_seats_availability([(slot, ticket)])[0] if slot else ticket.seats_available
|
||||
if ticket.seats_limited and ticket_seats_available <= 0:
|
||||
# Remove existing line if exists and do not add a new one
|
||||
# if no ticket is available anymore
|
||||
new_qty = existing_qty
|
||||
|
|
@ -48,20 +62,23 @@ class SaleOrder(models.Model):
|
|||
ticket=ticket.name,
|
||||
event=ticket.event_id.name,
|
||||
)
|
||||
elif ticket.seats_limited and qty_added > ticket.seats_available:
|
||||
new_qty = existing_qty + ticket.seats_available
|
||||
elif ticket.seats_limited and qty_added > ticket_seats_available:
|
||||
new_qty = existing_qty + ticket_seats_available
|
||||
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,
|
||||
'Sorry, only %(remaining_seats)d seats are still available for the %(ticket)s ticket for the %(event)s event%(slot)s.',
|
||||
remaining_seats=ticket_seats_available,
|
||||
slot=f' on {slot.name}' if slot else '',
|
||||
ticket=ticket.name,
|
||||
event=ticket.event_id.name,
|
||||
)
|
||||
|
||||
return new_qty, warning
|
||||
|
||||
def _prepare_order_line_values(self, product_id, quantity, event_ticket_id=False, **kwargs):
|
||||
def _prepare_order_line_values(self, product_id, *args, event_slot_id=False, event_ticket_id=False, **kwargs):
|
||||
"""Add corresponding event to the SOline creation values (if ticket is provided)."""
|
||||
values = super()._prepare_order_line_values(product_id, quantity, **kwargs)
|
||||
values = super()._prepare_order_line_values(
|
||||
product_id, *args, event_ticket_id=event_ticket_id, **kwargs,
|
||||
)
|
||||
|
||||
if not event_ticket_id:
|
||||
return values
|
||||
|
|
@ -73,42 +90,38 @@ class SaleOrder(models.Model):
|
|||
|
||||
values['event_id'] = ticket.event_id.id
|
||||
values['event_ticket_id'] = ticket.id
|
||||
values['event_slot_id'] = event_slot_id
|
||||
|
||||
return values
|
||||
|
||||
def _update_cart_line_values(self, order_line, update_values):
|
||||
"""Remove event registrations on quantity decrease."""
|
||||
def _cart_update_order_line(self, order_line, quantity, **kwargs):
|
||||
old_qty = order_line.product_uom_qty
|
||||
|
||||
super()._update_cart_line_values(order_line, update_values)
|
||||
if not order_line.event_ticket_id:
|
||||
return
|
||||
updated_line = super()._cart_update_order_line(order_line, quantity, **kwargs)
|
||||
|
||||
new_qty = order_line.product_uom_qty
|
||||
if new_qty < old_qty:
|
||||
attendees = self.env['event.registration'].search([
|
||||
('state', '!=', 'cancel'),
|
||||
('sale_order_id', '=', self.id),
|
||||
('event_ticket_id', '=', order_line.event_ticket_id.id),
|
||||
], offset=new_qty, limit=(old_qty - new_qty), order='create_date asc')
|
||||
# Remove event registrations on quantity decrease.
|
||||
if (
|
||||
updated_line
|
||||
and updated_line.event_ticket_id
|
||||
and (diff := old_qty - updated_line.product_uom_qty) > 0
|
||||
):
|
||||
attendees = self.env['event.registration'].search(
|
||||
domain=[
|
||||
('state', '!=', 'cancel'),
|
||||
('sale_order_id', '=', self.id),
|
||||
('event_slot_id', '=', order_line.event_slot_id.id),
|
||||
('event_ticket_id', '=', order_line.event_ticket_id.id),
|
||||
],
|
||||
offset=updated_line.product_uom_qty,
|
||||
limit=diff,
|
||||
order='create_date asc',
|
||||
)
|
||||
attendees.action_cancel()
|
||||
|
||||
return updated_line
|
||||
|
||||
def _filter_can_send_abandoned_cart_mail(self):
|
||||
"""Prevent carts with expired/sold out tickets from being subject of reminder emails."""
|
||||
# Prevent carts with expired/sold out tickets from being subject of reminder emails
|
||||
return super()._filter_can_send_abandoned_cart_mail().filtered(
|
||||
lambda so: all(ticket.sale_available for ticket in so.order_line.event_ticket_id)
|
||||
lambda so: all(ticket.sale_available for ticket in so.order_line.event_ticket_id),
|
||||
)
|
||||
|
||||
|
||||
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
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import api, models
|
||||
|
||||
|
||||
class SaleOrderLine(models.Model):
|
||||
_inherit = 'sale.order.line'
|
||||
|
||||
@api.depends('product_id.display_name', 'event_ticket_id.display_name')
|
||||
def _compute_name_short(self):
|
||||
""" Override of `website_sale` to replace the product name with the ticket name. """
|
||||
super()._compute_name_short()
|
||||
|
||||
for line in self:
|
||||
if line.event_ticket_id:
|
||||
line.name_short = line.event_ticket_id.display_name
|
||||
|
||||
def _should_show_strikethrough_price(self):
|
||||
""" Override of `website_sale` to hide the strikethrough price for events. """
|
||||
return super()._should_show_strikethrough_price() and not self.event_id
|
||||
|
||||
def _is_reorder_allowed(self):
|
||||
return not self.event_id and super()._is_reorder_allowed()
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
# -*- 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() + [('detailed_type', '!=', 'event')]
|
||||
Loading…
Add table
Add a link
Reference in a new issue