Files
odoo_source/addons/event_sale/models/event.py
T
ptr 0f41256009 [ADD] mail,sale,stock,purchase,event,pos: Source document clickable in chatter
PURPOSE:
The source document should be in the chatter and clickable

NEW MAIL TEMPLATE:
mail: new template 'message_origin_link' with clickable link to origin
Variables to pass:
- origin: the record from which the current record had been created
- self: The current record
Optional:
- edit: If true, the record has been modified. Otherwise it has been created
  from the origin

SPECIFICATION:
Source Document is available in following models
1) After creating SO then Sale to Invoice -> Source Document (After creating Sales Order and then clicking on Create invoice)
2) When procurement is created after SO or MO or Order Point(procurement.order) - > Source Document
3) Stock.picking -> Source Document ( After Creating SO or PO)
4) When Manufacturing Order is Created (mrp.production) -> Source Document (Coming after creating a sale order of product)
5) Event -> Attendees(event.registration) -> Source Document
6) Request For Quotation -> Source Document (After creating Purchase Tender, SO)
7) In Purchase Tender(purchase.requisition) -> Source Document (When a new Purchase Tender is Created)
8) After creating PO then create invoice(vendor bill)-> Source Document
9) After creating Invoice from contract (subscription) - > source Document.
10) Refund invoice from Invoice --> Source Document.
11) Return picking from picking --> Source Document.
12) sale use POS to create invoice and picking -->  Source Document.

MESSAGES TO DISPLAY:
-In Customer Invoice, there is a source document of Sale Order.
 "This Invoice has been created from Sale Order(s): SO001, SO002"

-In Procurement, the source document can be either of Sale Order or Manufacturing Order or Order Point.
 "This procurement is created from: SO001 or MO0001 or OP/0001"

-In Stock Picking, the source document can be either of Sale Order or Purchase Order.
 "This transfer has been created from sales order(s): SO001 or PO0001"

-Create new Sales order of manufactured product , there will be Source Document with that Sale Order number
"This production has been created from procurement(s): WH: Stock -> CustomersMTO"

-When registering for Event from website, Sale Order is Created and it is stored in Source Document,
 "The attendee has been created from Sale order: SO001"

-In RFQ, the source document can be either Purchase Tender or Sale Order or Order Point,
 "This purchase order has been created from purchase requisition(s): TE0001 or SO001 or OP/0001"

-In Purchase Tender, the source document can be either of Sale Order/ Manufacturing Order/ Order Point.
 "This Purchase Requisition has been created from: WH: Stock -> CustomersMTO"

-In Vendor bill, there is a source document of Purchase Order.
 "This Vendor bill has been created from Purchase Order(s): PO0001, PO002"

-When creating refund of invoice
 "This customer invoices refund has been created from customer invoices: INV/2016/0001"

-when create invoice and picking form pos.
 "This invoce has been create from point of sale: MainXX"
2016-06-02 15:33:57 +02:00

166 lines
7.3 KiB
Python

# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import api, fields, models, _
from odoo.exceptions import ValidationError
import odoo.addons.decimal_precision as dp
class Event(models.Model):
_inherit = 'event.event'
def _default_tickets(self):
product = self.env.ref('event_sale.product_product_event', raise_if_not_found=False)
if not product:
return self.env['event.event.ticket']
return [{
'name': _('Registration'),
'product_id': product.id,
'price': 0,
}]
event_ticket_ids = fields.One2many('event.event.ticket', 'event_id', string='Event Ticket',
default=lambda self: self._default_tickets(), copy=True)
class EventTicket(models.Model):
_name = 'event.event.ticket'
_description = 'Event Ticket'
def _default_product_id(self):
return self.env.ref('event_sale.product_product_event', raise_if_not_found=False)
name = fields.Char(string='Name', required=True, translate=True)
event_id = fields.Many2one('event.event', string="Event", required=True, ondelete='cascade')
product_id = fields.Many2one('product.product', string='Product',
required=True, domain=[("event_ok", "=", True)], default=_default_product_id)
registration_ids = fields.One2many('event.registration', 'event_ticket_id', string='Registrations')
price = fields.Float(string='Price', digits=dp.get_precision('Product Price'))
deadline = fields.Date(string="Sales End")
is_expired = fields.Boolean(string='Is Expired', compute='_compute_is_expired')
price_reduce = fields.Float(string="Price Reduce", compute="_compute_price_reduce", digits=dp.get_precision('Product Price'))
# seats fields
seats_availability = fields.Selection([('limited', 'Limited'), ('unlimited', 'Unlimited')],
string='Available Seat', required=True, store=True, compute='_compute_seats', default="limited")
seats_max = fields.Integer(string='Maximum Available Seats',
help="Define the number of available tickets. If you have too much registrations you will "
"not be able to sell tickets anymore. Set 0 to ignore this rule set as unlimited.")
seats_reserved = fields.Integer(string='Reserved Seats', compute='_compute_seats', store=True)
seats_available = fields.Integer(string='Available Seats', compute='_compute_seats', store=True)
seats_unconfirmed = fields.Integer(string='Unconfirmed Seat Reservations', compute='_compute_seats', store=True)
seats_used = fields.Integer(compute='_compute_seats', store=True)
@api.multi
def _compute_is_expired(self):
for record in self:
if record.deadline:
current_date = fields.Date.context_today(record.with_context({'tz': record.event_id.date_tz}))
record.is_expired = record.deadline < current_date
else:
record.is_expired = False
@api.multi
def _compute_price_reduce(self):
for record in self:
product = record.product_id
discount = product.lst_price and (product.lst_price - product.price) / product.lst_price or 0.0
record.price_reduce = (1.0 - discount) * record.price
@api.multi
@api.depends('seats_max', 'registration_ids.state')
def _compute_seats(self):
""" Determine reserved, available, reserved but unconfirmed and used seats. """
# initialize fields to 0 + compute seats availability
for ticket in self:
ticket.seats_availability = 'unlimited' if ticket.seats_max == 0 else 'limited'
ticket.seats_unconfirmed = ticket.seats_reserved = ticket.seats_used = ticket.seats_available = 0
# aggregate registrations by ticket and by state
if self.ids:
state_field = {
'draft': 'seats_unconfirmed',
'open': 'seats_reserved',
'done': 'seats_used',
}
query = """ SELECT event_ticket_id, state, count(event_id)
FROM event_registration
WHERE event_ticket_id IN %s AND state IN ('draft', 'open', 'done')
GROUP BY event_ticket_id, state
"""
self.env.cr.execute(query, (tuple(self.ids),))
for event_ticket_id, state, num in self.env.cr.fetchall():
ticket = self.browse(event_ticket_id)
ticket[state_field[state]] += num
# compute seats_available
for ticket in self:
if ticket.seats_max > 0:
ticket.seats_available = ticket.seats_max - (ticket.seats_reserved + ticket.seats_used)
@api.multi
@api.constrains('registration_ids', 'seats_max')
def _check_seats_limit(self):
for record in self:
if record.seats_max and record.seats_available < 0:
raise ValidationError(_('No more available seats for the ticket'))
@api.onchange('product_id')
def _onchange_product_id(self):
self.price = self.product_id.list_price or 0
class EventRegistration(models.Model):
_inherit = 'event.registration'
event_ticket_id = fields.Many2one('event.event.ticket', string='Event Ticket')
# in addition to origin generic fields, add real relational fields to correctly
# handle attendees linked to sale orders and their lines
# TDE FIXME: maybe add an onchange on sale_order_id + origin
sale_order_id = fields.Many2one('sale.order', string='Source Sale Order', ondelete='cascade')
sale_order_line_id = fields.Many2one('sale.order.line', string='Sale Order Line', ondelete='cascade')
@api.multi
@api.constrains('event_ticket_id', 'state')
def _check_ticket_seats_limit(self):
for record in self:
if record.event_ticket_id.seats_max and record.event_ticket_id.seats_available < 0:
raise ValidationError(_('No more available seats for this ticket'))
@api.multi
def _check_auto_confirmation(self):
res = super(EventRegistration, self)._check_auto_confirmation()
if res:
orders = self.env['sale.order'].search([('state', '=', 'draft'), ('id', 'in', self.mapped('sale_order_id').ids)], limit=1)
if orders:
res = False
return res
@api.model
def create(self, vals):
res = super(EventRegistration, self).create(vals)
if res.origin or res.sale_order_id:
res.message_post_with_view('mail.message_origin_link',
values={'self': res, 'origin': res.sale_order_id},
subtype_id=self.env.ref('mail.mt_note').id)
return res
@api.model
def _prepare_attendee_values(self, registration):
""" Override to add sale related stuff """
line_id = registration.get('sale_order_line_id')
if line_id:
registration.setdefault('partner_id', line_id.order_id.partner_id)
att_data = super(EventRegistration, self)._prepare_attendee_values(registration)
if line_id:
att_data.update({
'event_id': line_id.event_id.id,
'event_id': line_id.event_id.id,
'event_ticket_id': line_id.event_ticket_id.id,
'origin': line_id.order_id.name,
'sale_order_id': line_id.order_id.id,
'sale_order_line_id': line_id.id,
})
return att_data