diff options
| author | stephanchrst <stephanchrst@gmail.com> | 2022-05-10 21:51:50 +0700 |
|---|---|---|
| committer | stephanchrst <stephanchrst@gmail.com> | 2022-05-10 21:51:50 +0700 |
| commit | 3751379f1e9a4c215fb6eb898b4ccc67659b9ace (patch) | |
| tree | a44932296ef4a9b71d5f010906253d8c53727726 /addons/event_sale/models/sale_order.py | |
| parent | 0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (diff) | |
initial commit 2
Diffstat (limited to 'addons/event_sale/models/sale_order.py')
| -rw-r--r-- | addons/event_sale/models/sale_order.py | 160 |
1 files changed, 160 insertions, 0 deletions
diff --git a/addons/event_sale/models/sale_order.py b/addons/event_sale/models/sale_order.py new file mode 100644 index 00000000..bf3aca6c --- /dev/null +++ b/addons/event_sale/models/sale_order.py @@ -0,0 +1,160 @@ +# -*- coding: utf-8 -*- + +from odoo import api, fields, models, _ + + +class SaleOrder(models.Model): + _inherit = "sale.order" + + attendee_count = fields.Integer('Attendee Count', compute='_compute_attendee_count') + + def write(self, vals): + """ Synchronize partner from SO to registrations. This is done notably + in website_sale controller shop/address that updates customer, but not + only. """ + result = super(SaleOrder, self).write(vals) + if vals.get('partner_id'): + registrations_toupdate = self.env['event.registration'].search([('sale_order_id', 'in', self.ids)]) + registrations_toupdate.write({'partner_id': vals['partner_id']}) + return result + + def action_confirm(self): + res = super(SaleOrder, self).action_confirm() + for so in self: + # confirm registration if it was free (otherwise it will be confirmed once invoice fully paid) + so.order_line._update_registrations(confirm=so.amount_total == 0, cancel_to_draft=False) + if any(line.event_id for line in so.order_line): + return self.env['ir.actions.act_window'] \ + .with_context(default_sale_order_id=so.id) \ + ._for_xml_id('event_sale.action_sale_order_event_registration') + return res + + def action_cancel(self): + self.order_line._cancel_associated_registrations() + return super(SaleOrder, self).action_cancel() + + def action_view_attendee_list(self): + action = self.env["ir.actions.actions"]._for_xml_id("event.event_registration_action_tree") + action['domain'] = [('sale_order_id', 'in', self.ids)] + return action + + def _compute_attendee_count(self): + sale_orders_data = self.env['event.registration'].read_group( + [('sale_order_id', 'in', self.ids)], + ['sale_order_id'], ['sale_order_id'] + ) + attendee_count_data = { + sale_order_data['sale_order_id'][0]: + sale_order_data['sale_order_id_count'] + for sale_order_data in sale_orders_data + } + for sale_order in self: + sale_order.attendee_count = attendee_count_data.get(sale_order.id, 0) + + def unlink(self): + self.mapped('order_line')._unlink_associated_registrations() + return super(SaleOrder, self).unlink() + + +class SaleOrderLine(models.Model): + + _inherit = 'sale.order.line' + + event_id = fields.Many2one( + 'event.event', string='Event', + help="Choose an event and it will automatically create a registration for this event.") + event_ticket_id = fields.Many2one( + 'event.event.ticket', string='Event Ticket', + help="Choose an event ticket and it will automatically create a registration for this event ticket.") + event_ok = fields.Boolean(related='product_id.event_ok', readonly=True) + + @api.depends('state', 'event_id') + def _compute_product_uom_readonly(self): + event_lines = self.filtered(lambda line: line.event_id) + event_lines.update({'product_uom_readonly': True}) + super(SaleOrderLine, self - event_lines)._compute_product_uom_readonly() + + def _update_registrations(self, confirm=True, cancel_to_draft=False, registration_data=None, mark_as_paid=False): + """ Create or update registrations linked to a sales order line. A sale + order line has a product_uom_qty attribute that will be the number of + registrations linked to this line. This method update existing registrations + and create new one for missing one. """ + RegistrationSudo = self.env['event.registration'].sudo() + registrations = RegistrationSudo.search([('sale_order_line_id', 'in', self.ids)]) + registrations_vals = [] + for so_line in self.filtered('event_id'): + existing_registrations = registrations.filtered(lambda self: self.sale_order_line_id.id == so_line.id) + if confirm: + existing_registrations.filtered(lambda self: self.state not in ['open', 'cancel']).action_confirm() + if mark_as_paid: + existing_registrations.filtered(lambda self: not self.is_paid)._action_set_paid() + if cancel_to_draft: + existing_registrations.filtered(lambda self: self.state == 'cancel').action_set_draft() + + for count in range(int(so_line.product_uom_qty) - len(existing_registrations)): + values = { + 'sale_order_line_id': so_line.id, + 'sale_order_id': so_line.order_id.id + } + # TDE CHECK: auto confirmation + if registration_data: + values.update(registration_data.pop()) + registrations_vals.append(values) + + if registrations_vals: + RegistrationSudo.create(registrations_vals) + return True + + @api.onchange('product_id') + def _onchange_product_id(self): + # We reset the event when keeping it would lead to an inconstitent state. + # We need to do it this way because the only relation between the product and the event is through the corresponding tickets. + if self.event_id and (not self.product_id or self.product_id.id not in self.event_id.mapped('event_ticket_ids.product_id.id')): + self.event_id = None + + @api.onchange('event_id') + def _onchange_event_id(self): + # We reset the ticket when keeping it would lead to an inconstitent state. + if self.event_ticket_id and (not self.event_id or self.event_id != self.event_ticket_id.event_id): + self.event_ticket_id = None + + @api.onchange('product_uom', 'product_uom_qty') + def product_uom_change(self): + if not self.event_ticket_id: + super(SaleOrderLine, self).product_uom_change() + + @api.onchange('event_ticket_id') + def _onchange_event_ticket_id(self): + # we call this to force update the default name + self.product_id_change() + + def unlink(self): + self._unlink_associated_registrations() + return super(SaleOrderLine, self).unlink() + + def _cancel_associated_registrations(self): + self.env['event.registration'].search([('sale_order_line_id', 'in', self.ids)]).action_cancel() + + def _unlink_associated_registrations(self): + self.env['event.registration'].search([('sale_order_line_id', 'in', self.ids)]).unlink() + + def get_sale_order_line_multiline_description_sale(self, product): + """ We override this method because we decided that: + The default description of a sales order line containing a ticket must be different than the default description when no ticket is present. + So in that case we use the description computed from the ticket, instead of the description computed from the product. + We need this override to be defined here in sales order line (and not in product) because here is the only place where the event_ticket_id is referenced. + """ + if self.event_ticket_id: + ticket = self.event_ticket_id.with_context( + lang=self.order_id.partner_id.lang, + ) + + return ticket._get_ticket_multiline_description() + self._get_sale_order_line_multiline_description_variants() + else: + return super(SaleOrderLine, self).get_sale_order_line_multiline_description_sale(product) + + def _get_display_price(self, product): + if self.event_ticket_id and self.event_id: + return self.event_ticket_id.with_context(pricelist=self.order_id.pricelist_id.id, uom=self.product_uom.id).price_reduce + else: + return super()._get_display_price(product) |
