From 97e6443089a351647bc8be64a18bd74698220add Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Fri, 3 Mar 2017 11:32:12 +0100 Subject: [PATCH 1/8] [IMP] mail: improve default recipients computation When computing default recipients to mail on some records, take into account models having a partner_email field. Indeed this method checks for some commonly-used partner or email fields to find recipients. This allows to avoid having custom methods in each model. This commit adds support for partner_email email field used notably in event and track management. --- addons/mail/models/mail_thread.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/addons/mail/models/mail_thread.py b/addons/mail/models/mail_thread.py index 06918b75551..54921dbb88c 100644 --- a/addons/mail/models/mail_thread.py +++ b/addons/mail/models/mail_thread.py @@ -734,6 +734,8 @@ class MailThread(models.AbstractModel): recipient_ids.add(record.partner_id.id) elif 'email_from' in self._fields and record.email_from: email_to = record.email_from + elif 'partner_email' in self._fields and record.partner_email: + email_to = record.partner_email elif 'email' in self._fields: email_to = record.email res[record.id] = {'partner_ids': list(recipient_ids), 'email_to': email_to, 'email_cc': email_cc} From 66d8567a252207275ee8c22200ae28d2e342dab3 Mon Sep 17 00:00:00 2001 From: Mitali Patel Date: Thu, 9 Feb 2017 10:08:41 +0100 Subject: [PATCH 2/8] [LINT] event_*: apply small linting and guidelines No functional change is implied by this commit. Some code is moved and some files are renamed. --- addons/event/models/event.py | 151 +++--- addons/event_sale/models/event.py | 2 - addons/website_event/__manifest__.py | 10 +- ...{website_event_data.xml => event_data.xml} | 0 ...{website_event_demo.xml => event_demo.xml} | 0 ..._event_security.xml => event_security.xml} | 0 ...vent_templates.xml => event_templates.xml} | 0 ...ebsite_event_views.xml => event_views.xml} | 0 .../website_event_questions/__manifest__.py | 6 +- .../data/{demo.xml => event_demo.xml} | 0 ...ions_templates.xml => event_templates.xml} | 0 ..._questions_backend.xml => event_views.xml} | 0 addons/website_event_sale/__manifest__.py | 2 +- ...sale_templates.xml => event_templates.xml} | 0 addons/website_event_track/__manifest__.py | 9 +- .../website_event_track/data/event_demo.xml | 448 +++++++++++++++--- ...nt_track_data.xml => event_track_data.xml} | 0 .../data/website_event_track_demo.xml | 325 ------------- addons/website_event_track/models/__init__.py | 2 +- ...{website_event_track.py => event_track.py} | 21 +- ..._security.xml => event_track_security.xml} | 0 ...emplates.xml => event_track_templates.xml} | 0 ..._track_views.xml => event_track_views.xml} | 0 23 files changed, 482 insertions(+), 494 deletions(-) rename addons/website_event/data/{website_event_data.xml => event_data.xml} (100%) rename addons/website_event/data/{website_event_demo.xml => event_demo.xml} (100%) rename addons/website_event/security/{website_event_security.xml => event_security.xml} (100%) rename addons/website_event/views/{website_event_templates.xml => event_templates.xml} (100%) rename addons/website_event/views/{website_event_views.xml => event_views.xml} (100%) rename addons/website_event_questions/data/{demo.xml => event_demo.xml} (100%) rename addons/website_event_questions/views/{website_event_questions_templates.xml => event_templates.xml} (100%) rename addons/website_event_questions/views/{website_event_questions_backend.xml => event_views.xml} (100%) rename addons/website_event_sale/views/{website_event_sale_templates.xml => event_templates.xml} (100%) rename addons/website_event_track/data/{website_event_track_data.xml => event_track_data.xml} (100%) delete mode 100644 addons/website_event_track/data/website_event_track_demo.xml rename addons/website_event_track/models/{website_event_track.py => event_track.py} (99%) rename addons/website_event_track/security/{website_event_track_security.xml => event_track_security.xml} (100%) rename addons/website_event_track/views/{website_event_track_templates.xml => event_track_templates.xml} (100%) rename addons/website_event_track/views/{website_event_track_views.xml => event_track_views.xml} (100%) diff --git a/addons/event/models/event.py b/addons/event/models/event.py index b07ec585b9f..6265c5f4610 100644 --- a/addons/event/models/event.py +++ b/addons/event/models/event.py @@ -32,6 +32,24 @@ class EventEvent(models.Model): _inherit = ['mail.thread'] _order = 'date_begin' + @api.model + def _default_event_mail_ids(self): + return [(0, 0, { + 'interval_unit': 'now', + 'interval_type': 'after_sub', + 'template_id': self.env.ref('event.event_subscription') + }), (0, 0, { + 'interval_nbr': 1, + 'interval_unit': 'days', + 'interval_type': 'before_event', + 'template_id': self.env.ref('event.event_reminder') + }), (0, 0, { + 'interval_nbr': 10, + 'interval_unit': 'days', + 'interval_type': 'before_event', + 'template_id': self.env.ref('event.event_reminder') + })] + name = fields.Char( string='Event Name', translate=True, required=True, readonly=False, states={'done': [('readonly', True)]}) @@ -52,25 +70,7 @@ class EventEvent(models.Model): readonly=False, states={'done': [('readonly', True)]}, oldname='type') color = fields.Integer('Kanban Color Index') - event_mail_ids = fields.One2many('event.mail', 'event_id', string='Mail Schedule', default=lambda self: self._default_event_mail_ids(), copy=True) - - @api.model - def _default_event_mail_ids(self): - return [(0, 0, { - 'interval_unit': 'now', - 'interval_type': 'after_sub', - 'template_id': self.env.ref('event.event_subscription') - }), (0, 0, { - 'interval_nbr': 1, - 'interval_unit': 'days', - 'interval_type': 'before_event', - 'template_id': self.env.ref('event.event_reminder') - }), (0, 0, { - 'interval_nbr': 10, - 'interval_unit': 'days', - 'interval_type': 'before_event', - 'template_id': self.env.ref('event.event_reminder') - })] + event_mail_ids = fields.One2many('event.mail', 'event_id', string='Mail Schedule', default=_default_event_mail_ids, copy=True) # Seats and computation seats_max = fields.Integer( @@ -99,6 +99,44 @@ class EventEvent(models.Model): string='Number of Expected Attendees', readonly=True, compute='_compute_seats') + # Registration fields + registration_ids = fields.One2many( + 'event.registration', 'event_id', string='Attendees', + readonly=False, states={'done': [('readonly', True)]}) + # Date fields + date_tz = fields.Selection('_tz_get', string='Timezone', required=True, default=lambda self: self.env.user.tz) + date_begin = fields.Datetime( + string='Start Date', required=True, + track_visibility='onchange', states={'done': [('readonly', True)]}) + date_end = fields.Datetime( + string='End Date', required=True, + track_visibility='onchange', states={'done': [('readonly', True)]}) + date_begin_located = fields.Char(string='Start Date Located', compute='_compute_date_begin_tz') + date_end_located = fields.Char(string='End Date Located', compute='_compute_date_end_tz') + + state = fields.Selection([ + ('draft', 'Unconfirmed'), ('cancel', 'Cancelled'), + ('confirm', 'Confirmed'), ('done', 'Done')], + string='Status', default='draft', readonly=True, required=True, copy=False, + help="If event is created, the status is 'Draft'. If event is confirmed for the particular dates the status is set to 'Confirmed'. If the event is over, the status is set to 'Done'. If event is cancelled the status is set to 'Cancelled'.") + auto_confirm = fields.Boolean(string='Confirmation not required', compute='_compute_auto_confirm') + reply_to = fields.Char( + 'Reply-To Email', readonly=False, states={'done': [('readonly', True)]}, + help="The email address of the organizer is likely to be put here, with the effect to be in the 'Reply-To' of the mails sent automatically at event or registrations confirmation. You can also put the email address of your mail gateway if you use one.") + address_id = fields.Many2one( + 'res.partner', string='Location', default=lambda self: self.env.user.company_id.partner_id, + readonly=False, states={'done': [('readonly', True)]}) + country_id = fields.Many2one('res.country', 'Country', related='address_id.country_id', store=True) + description = fields.Html( + string='Description', oldname='note', translate=html_translate, sanitize_attributes=False, + readonly=False, states={'done': [('readonly', True)]}) + # badge fields + badge_front = fields.Html(string='Badge Front') + badge_back = fields.Html(string='Badge Back') + badge_innerleft = fields.Html(string='Badge Inner Left') + badge_innerright = fields.Html(string='Badge Inner Right') + event_logo = fields.Html(string='Event Logo') + @api.multi @api.depends('seats_max', 'registration_ids.state') def _compute_seats(self): @@ -128,21 +166,6 @@ class EventEvent(models.Model): event.seats_available = event.seats_max - (event.seats_reserved + event.seats_used) event.seats_expected = event.seats_unconfirmed + event.seats_reserved + event.seats_used - # Registration fields - registration_ids = fields.One2many( - 'event.registration', 'event_id', string='Attendees', - readonly=False, states={'done': [('readonly', True)]}) - # Date fields - date_tz = fields.Selection('_tz_get', string='Timezone', required=True, default=lambda self: self.env.user.tz) - date_begin = fields.Datetime( - string='Start Date', required=True, - track_visibility='onchange', states={'done': [('readonly', True)]}) - date_end = fields.Datetime( - string='End Date', required=True, - track_visibility='onchange', states={'done': [('readonly', True)]}) - date_begin_located = fields.Char(string='Start Date Located', compute='_compute_date_begin_tz') - date_end_located = fields.Char(string='End Date Located', compute='_compute_date_end_tz') - @api.model def _tz_get(self): return [(x, x) for x in pytz.all_timezones] @@ -163,45 +186,16 @@ class EventEvent(models.Model): else: self.date_end_located = False - state = fields.Selection([ - ('draft', 'Unconfirmed'), ('cancel', 'Cancelled'), - ('confirm', 'Confirmed'), ('done', 'Done')], - string='Status', default='draft', readonly=True, required=True, copy=False, - help="If event is created, the status is 'Draft'. If event is confirmed for the particular dates the status is set to 'Confirmed'. If the event is over, the status is set to 'Done'. If event is cancelled the status is set to 'Cancelled'.") - auto_confirm = fields.Boolean(string='Confirmation not required', compute='_compute_auto_confirm') - @api.one def _compute_auto_confirm(self): self.auto_confirm = self.env['ir.values'].get_default('event.config.settings', 'default_auto_confirmation') - reply_to = fields.Char( - 'Reply-To Email', readonly=False, states={'done': [('readonly', True)]}, - help="The email address of the organizer is likely to be put here, with the effect to be in the 'Reply-To' of the mails sent automatically at event or registrations confirmation. You can also put the email address of your mail gateway if you use one.") - address_id = fields.Many2one( - 'res.partner', string='Location', default=lambda self: self.env.user.company_id.partner_id, - readonly=False, states={'done': [('readonly', True)]}) - country_id = fields.Many2one('res.country', 'Country', related='address_id.country_id', store=True) - description = fields.Html( - string='Description', oldname='note', translate=html_translate, sanitize_attributes=False, - readonly=False, states={'done': [('readonly', True)]}) - # badge fields - badge_front = fields.Html(string='Badge Front') - badge_back = fields.Html(string='Badge Back') - badge_innerleft = fields.Html(string='Badge Inner Left') - badge_innerright = fields.Html(string='Badge Inner Right') - event_logo = fields.Html(string='Event Logo') - - @api.multi - @api.depends('name', 'date_begin', 'date_end') - def name_get(self): - result = [] - for event in self: - date_begin = fields.Datetime.from_string(event.date_begin) - date_end = fields.Datetime.from_string(event.date_end) - dates = [fields.Date.to_string(fields.Datetime.context_timestamp(event, dt)) for dt in [date_begin, date_end] if dt] - dates = sorted(set(dates)) - result.append((event.id, '%s (%s)' % (event.name, ' - '.join(dates)))) - return result + @api.onchange('event_type_id') + def _onchange_type(self): + if self.event_type_id: + self.seats_min = self.event_type_id.default_registration_min + self.seats_max = self.event_type_id.default_registration_max + self.reply_to = self.event_type_id.default_reply_to @api.one @api.constrains('seats_max', 'seats_available') @@ -215,6 +209,18 @@ class EventEvent(models.Model): if self.date_end < self.date_begin: raise ValidationError(_('Closing Date cannot be set before Beginning Date.')) + @api.multi + @api.depends('name', 'date_begin', 'date_end') + def name_get(self): + result = [] + for event in self: + date_begin = fields.Datetime.from_string(event.date_begin) + date_end = fields.Datetime.from_string(event.date_end) + dates = [fields.Date.to_string(fields.Datetime.context_timestamp(event, dt)) for dt in [date_begin, date_end] if dt] + dates = sorted(set(dates)) + result.append((event.id, '%s (%s)' % (event.name, ' - '.join(dates)))) + return result + @api.model def create(self, vals): res = super(EventEvent, self).create(vals) @@ -251,13 +257,6 @@ class EventEvent(models.Model): def button_confirm(self): self.state = 'confirm' - @api.onchange('event_type_id') - def _onchange_type(self): - if self.event_type_id: - self.seats_min = self.event_type_id.default_registration_min - self.seats_max = self.event_type_id.default_registration_max - self.reply_to = self.event_type_id.default_reply_to - @api.multi def action_event_registration_report(self): res = self.env['ir.actions.act_window'].for_xml_id('event', 'action_report_event_registration') diff --git a/addons/event_sale/models/event.py b/addons/event_sale/models/event.py index 5eba5703918..fb2d843c349 100644 --- a/addons/event_sale/models/event.py +++ b/addons/event_sale/models/event.py @@ -8,7 +8,6 @@ import odoo.addons.decimal_precision as dp class Event(models.Model): - _inherit = 'event.event' def _default_tickets(self): @@ -26,7 +25,6 @@ class Event(models.Model): class EventTicket(models.Model): - _name = 'event.event.ticket' _description = 'Event Ticket' diff --git a/addons/website_event/__manifest__.py b/addons/website_event/__manifest__.py index 13d42d483be..bd467c9b02a 100644 --- a/addons/website_event/__manifest__.py +++ b/addons/website_event/__manifest__.py @@ -11,15 +11,15 @@ Online Events """, 'depends': ['website', 'website_partner', 'website_mail', 'event'], 'data': [ - 'data/website_event_data.xml', + 'data/event_data.xml', 'views/event_config_settings_views.xml', - 'views/website_event_templates.xml', - 'views/website_event_views.xml', + 'views/event_templates.xml', + 'views/event_views.xml', 'security/ir.model.access.csv', - 'security/website_event_security.xml', + 'security/event_security.xml', ], 'demo': [ - 'data/website_event_demo.xml' + 'data/event_demo.xml' ], 'application': True, } diff --git a/addons/website_event/data/website_event_data.xml b/addons/website_event/data/event_data.xml similarity index 100% rename from addons/website_event/data/website_event_data.xml rename to addons/website_event/data/event_data.xml diff --git a/addons/website_event/data/website_event_demo.xml b/addons/website_event/data/event_demo.xml similarity index 100% rename from addons/website_event/data/website_event_demo.xml rename to addons/website_event/data/event_demo.xml diff --git a/addons/website_event/security/website_event_security.xml b/addons/website_event/security/event_security.xml similarity index 100% rename from addons/website_event/security/website_event_security.xml rename to addons/website_event/security/event_security.xml diff --git a/addons/website_event/views/website_event_templates.xml b/addons/website_event/views/event_templates.xml similarity index 100% rename from addons/website_event/views/website_event_templates.xml rename to addons/website_event/views/event_templates.xml diff --git a/addons/website_event/views/website_event_views.xml b/addons/website_event/views/event_views.xml similarity index 100% rename from addons/website_event/views/website_event_views.xml rename to addons/website_event/views/event_views.xml diff --git a/addons/website_event_questions/__manifest__.py b/addons/website_event_questions/__manifest__.py index cb29d3087f7..78200c5469e 100644 --- a/addons/website_event_questions/__manifest__.py +++ b/addons/website_event_questions/__manifest__.py @@ -7,13 +7,13 @@ 'version': '1.0', 'depends': ['website_event'], 'data': [ - 'views/website_event_questions_backend.xml', - 'views/website_event_questions_templates.xml', + 'views/event_views.xml', + 'views/event_templates.xml', 'report/report_event_question_view.xml', 'security/ir.model.access.csv', ], 'demo': [ - 'data/demo.xml', + 'data/event_demo.xml', ], 'installable': True, } diff --git a/addons/website_event_questions/data/demo.xml b/addons/website_event_questions/data/event_demo.xml similarity index 100% rename from addons/website_event_questions/data/demo.xml rename to addons/website_event_questions/data/event_demo.xml diff --git a/addons/website_event_questions/views/website_event_questions_templates.xml b/addons/website_event_questions/views/event_templates.xml similarity index 100% rename from addons/website_event_questions/views/website_event_questions_templates.xml rename to addons/website_event_questions/views/event_templates.xml diff --git a/addons/website_event_questions/views/website_event_questions_backend.xml b/addons/website_event_questions/views/event_views.xml similarity index 100% rename from addons/website_event_questions/views/website_event_questions_backend.xml rename to addons/website_event_questions/views/event_views.xml diff --git a/addons/website_event_sale/__manifest__.py b/addons/website_event_sale/__manifest__.py index c6176bac80b..4311b952800 100644 --- a/addons/website_event_sale/__manifest__.py +++ b/addons/website_event_sale/__manifest__.py @@ -12,7 +12,7 @@ Online Event's Tickets """, 'depends': ['website_event', 'event_sale', 'website_sale'], 'data': [ - 'views/website_event_sale_templates.xml', + 'views/event_templates.xml', 'security/ir.model.access.csv', 'security/website_event_sale_security.xml', ], diff --git a/addons/website_event_sale/views/website_event_sale_templates.xml b/addons/website_event_sale/views/event_templates.xml similarity index 100% rename from addons/website_event_sale/views/website_event_sale_templates.xml rename to addons/website_event_sale/views/event_templates.xml diff --git a/addons/website_event_track/__manifest__.py b/addons/website_event_track/__manifest__.py index 2c14338c3c3..205fd60287e 100644 --- a/addons/website_event_track/__manifest__.py +++ b/addons/website_event_track/__manifest__.py @@ -22,14 +22,13 @@ Adds support for: 'depends': ['website_event'], 'data': [ 'security/ir.model.access.csv', - 'security/website_event_track_security.xml', - 'data/website_event_track_data.xml', - 'views/website_event_track_templates.xml', - 'views/website_event_track_views.xml', + 'security/event_track_security.xml', + 'data/event_track_data.xml', + 'views/event_track_templates.xml', + 'views/event_track_views.xml', 'views/event_views.xml', ], 'demo': [ 'data/event_demo.xml', - 'data/website_event_track_demo.xml' ], } diff --git a/addons/website_event_track/data/event_demo.xml b/addons/website_event_track/data/event_demo.xml index 95584626633..02fa5a6cd64 100644 --- a/addons/website_event_track/data/event_demo.xml +++ b/addons/website_event_track/data/event_demo.xml @@ -1,75 +1,397 @@ - - Technical - - - Business - - - Lightning Talks - - - Round Table - - - - True - True - + + Technical + + + Business + + + Lightning Talks + + + Round Table + + + + True + True + - + - - True - + + True + - + - - - - - http://odoo.com - + + + + + http://odoo.com + - - - - - http://odoo.com - + + + + + http://odoo.com + - - - - - + + + + + - - - - - http://odoo.com - + + + + + http://odoo.com + + + + + http://facebook.com/odoo + +

+ Ayaan has in the IT sector since 20 years. He + develops software to help develop websites. He sold his + first company at 30 years old and manage to grow OpenCorp + from 1 to 55 employees mostly by reselling services on + Odoo. +

+ Ayaan is the author of several books, including Amazon best seller + "How Odoo will change the business world!". +

+
+
+ + + Le Foyer du lac + + + Theatre + + + Lauzelle + + + Foyer Royal + + + Biereau + + + Bruyère + + + How to develop a website module. + + + + + + + 3 + draft + + + + How to integrate hardware materials with the Odoo point of sale. + + + + + + + confirmed + + + How to develop real time apps, the website live chat module explained. + + + + + + + confirmed + + + How to develop automated tests in the Odoo web client. + + + + + + + published + + + The new way to promote your modules in the Apps platform and Odoo website. + + + + + + + announced + + + Detailed roadmap of accounting new modules and improvements for version 8. + + + + + + + announced + + + A technical explanation of Odoo as a CMS and a eCommerce platform for version 8. + + + + + + + published + + + Discover Odoo CRM: How to optimize your sales, from leads to sales orders. + + + + + + 2 + + published + + + How to use Odoo for your HR process: recruitment, leaves management, appraisals, expenses, etc. + + + + + + + 2 + + published + + + Raising qualitive insights with the survey app + + + + + + 5 + draft + + + Discover Odoo Point-of-Sale: Your shop ready to use in 30 minutes. + + + + + + + confirmed + + + Manage your events with Odoo, the new training modules. + + + + + + + announced + + + Advanced reporting with Google Spreadsheets integration. + + + + + + + published + + + New Paypal modules (portal, handling, installments). + + + + + + + published + + + Odoo Mobile for Notes, Meetings and Messages. + + + + + + + announced + + + Odoo as your Enterprise Social Network. + + + + + + + draft + + + The Art of Making an Odoo Demo. + + + + + + + draft + + + How to build your marketing strategy for the purpose of generating leads with Odoo. + + + + + + 5 + + confirmed + + + Advanced lead management with Odoo: tips and tricks from the fields + + + + + + 5 + + confirmed + + + New Certification Program (valid from Oct. 2013). + + + + + + + confirmed + + + Recruiting high skilled talents with Odoo HR apps + + + + + + 7 + confirmed + + + Manage your KPIs (recomended to openERP partners). + + + + + + + draft + + + Key Success factors selling Odoo. + + + + + + + announced + + + Merge proposals review, code sprint (entire day). + + + + + + + announced + + + Merge proposals review, code sprint (entire afternoon) + + + + + + + announced + + + Odoo in 2014 + + + + + + published + 3 + + + Odoo Status & Strategy 2014 + + + + + + published + + + The new marketing strategy. + + + + + + published + 6 + + + Morning break + + + + + confirmed + + + Lunch + + + + + confirmed + - - - http://facebook.com/odoo - -

- Ayaan has in the IT sector since 20 years. He - develops software to help develop websites. He sold his - first company at 30 years old and manage to grow OpenCorp - from 1 to 55 employees mostly by reselling services on - Odoo. -

- Ayaan is the author of several books, including Amazon best seller - "How Odoo will change the business world!". -

-
-
diff --git a/addons/website_event_track/data/website_event_track_data.xml b/addons/website_event_track/data/event_track_data.xml similarity index 100% rename from addons/website_event_track/data/website_event_track_data.xml rename to addons/website_event_track/data/event_track_data.xml diff --git a/addons/website_event_track/data/website_event_track_demo.xml b/addons/website_event_track/data/website_event_track_demo.xml deleted file mode 100644 index 992bf209f25..00000000000 --- a/addons/website_event_track/data/website_event_track_demo.xml +++ /dev/null @@ -1,325 +0,0 @@ - - - - - Le Foyer du lac - - - Theatre - - - Lauzelle - - - Foyer Royal - - - Biereau - - - Bruyère - - - How to develop a website module. - - - - - - - 3 - draft - - - - How to integrate hardware materials with the Odoo point of sale. - - - - - - - confirmed - - - How to develop real time apps, the website live chat module explained. - - - - - - - confirmed - - - How to develop automated tests in the Odoo web client. - - - - - - - published - - - The new way to promote your modules in the Apps platform and Odoo website. - - - - - - - announced - - - Detailed roadmap of accounting new modules and improvements for version 8. - - - - - - - announced - - - A technical explanation of Odoo as a CMS and a eCommerce platform for version 8. - - - - - - - published - - - Discover Odoo CRM: How to optimize your sales, from leads to sales orders. - - - - - - 2 - - published - - - How to use Odoo for your HR process: recruitment, leaves management, appraisals, expenses, etc. - - - - - - - 2 - - published - - - Raising qualitive insights with the survey app - - - - - - 5 - draft - - - Discover Odoo Point-of-Sale: Your shop ready to use in 30 minutes. - - - - - - - confirmed - - - Manage your events with Odoo, the new training modules. - - - - - - - announced - - - Advanced reporting with Google Spreadsheets integration. - - - - - - - published - - - New Paypal modules (portal, handling, installments). - - - - - - - published - - - Odoo Mobile for Notes, Meetings and Messages. - - - - - - - announced - - - Odoo as your Enterprise Social Network. - - - - - - - draft - - - The Art of Making an Odoo Demo. - - - - - - - draft - - - How to build your marketing strategy for the purpose of generating leads with Odoo. - - - - - - 5 - - confirmed - - - Advanced lead management with Odoo: tips and tricks from the fields - - - - - - 5 - - confirmed - - - New Certification Program (valid from Oct. 2013). - - - - - - - confirmed - - - Recruiting high skilled talents with Odoo HR apps - - - - - - 7 - confirmed - - - Manage your KPIs (recomended to openERP partners). - - - - - - - draft - - - Key Success factors selling Odoo. - - - - - - - announced - - - Merge proposals review, code sprint (entire day). - - - - - - - announced - - - Merge proposals review, code sprint (entire afternoon) - - - - - - - announced - - - Odoo in 2014 - - - - - - published - 3 - - - Odoo Status & Strategy 2014 - - - - - - published - - - The new marketing strategy. - - - - - - published - 6 - - - Morning break - - - - - confirmed - - - Lunch - - - - - confirmed - - - diff --git a/addons/website_event_track/models/__init__.py b/addons/website_event_track/models/__init__.py index 8f0d1c76e14..3d479511cac 100644 --- a/addons/website_event_track/models/__init__.py +++ b/addons/website_event_track/models/__init__.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -import website_event_track +import event_track import event diff --git a/addons/website_event_track/models/website_event_track.py b/addons/website_event_track/models/event_track.py similarity index 99% rename from addons/website_event_track/models/website_event_track.py rename to addons/website_event_track/models/event_track.py index f6759fa999a..c7acc2f00a8 100644 --- a/addons/website_event_track/models/website_event_track.py +++ b/addons/website_event_track/models/event_track.py @@ -7,7 +7,6 @@ from odoo.addons.website.models.website import slug class TrackTag(models.Model): - _name = "event.track.tag" _description = 'Track Tag' _order = 'name' @@ -22,7 +21,6 @@ class TrackTag(models.Model): class TrackLocation(models.Model): - _name = "event.track.location" _description = 'Track Location' @@ -30,7 +28,6 @@ class TrackLocation(models.Model): class Track(models.Model): - _name = "event.track" _description = 'Event Track' _order = 'priority, date' @@ -61,6 +58,14 @@ class Track(models.Model): 'Priority', required=True, default='1') image = fields.Binary('Image', related='speaker_ids.image_medium', store=True, attachment=True) + @api.multi + @api.depends('name') + def _compute_website_url(self): + super(Track, self)._compute_website_url() + for track in self: + if not isinstance(track.id, models.NewId): + track.website_url = '/event/%s/track/%s' % (slug(track.event_id), slug(track)) + @api.model def create(self, vals): res = super(Track, self).create(vals) @@ -80,14 +85,6 @@ class Track(models.Model): self.message_subscribe([speaker['id'] for speaker in self.resolve_2many_commands('speaker_ids', vals['speaker_ids'], ['id'])]) return res - @api.multi - @api.depends('name') - def _compute_website_url(self): - super(Track, self)._compute_website_url() - for track in self: - if not isinstance(track.id, models.NewId): - track.website_url = '/event/%s/track/%s' % (slug(track.event_id), slug(track)) - @api.model def read_group(self, domain, fields, groupby, offset=0, limit=None, orderby=False, lazy=True): """ Override read_group to always display all states. """ @@ -131,7 +128,6 @@ class Track(models.Model): class SponsorType(models.Model): - _name = "event.sponsor.type" _order = "sequence" @@ -140,7 +136,6 @@ class SponsorType(models.Model): class Sponsor(models.Model): - _name = "event.sponsor" _order = "sequence" diff --git a/addons/website_event_track/security/website_event_track_security.xml b/addons/website_event_track/security/event_track_security.xml similarity index 100% rename from addons/website_event_track/security/website_event_track_security.xml rename to addons/website_event_track/security/event_track_security.xml diff --git a/addons/website_event_track/views/website_event_track_templates.xml b/addons/website_event_track/views/event_track_templates.xml similarity index 100% rename from addons/website_event_track/views/website_event_track_templates.xml rename to addons/website_event_track/views/event_track_templates.xml diff --git a/addons/website_event_track/views/website_event_track_views.xml b/addons/website_event_track/views/event_track_views.xml similarity index 100% rename from addons/website_event_track/views/website_event_track_views.xml rename to addons/website_event_track/views/event_track_views.xml From a650e5de58540b86100b231d1cc0f9a92a00e232 Mon Sep 17 00:00:00 2001 From: Mitali Patel Date: Thu, 9 Feb 2017 11:37:08 +0100 Subject: [PATCH 3/8] [IMP] event: improve event (mass) mailing Mass mailing option is activated on attendee and track models. Using the _mail_mass_mailing parameter on class allows to see those models in the mass mailing application without having bridge module. This commit also improves the scheduled mail form view and slighty improve labels related to scheduling mails on event. --- addons/event/models/event.py | 1 + addons/event/models/event_mail.py | 2 +- addons/event/views/event_views.xml | 51 +++++++++++-------- .../website_event_track/models/event_track.py | 1 + 4 files changed, 32 insertions(+), 23 deletions(-) diff --git a/addons/event/models/event.py b/addons/event/models/event.py index 6265c5f4610..b50dff53a59 100644 --- a/addons/event/models/event.py +++ b/addons/event/models/event.py @@ -277,6 +277,7 @@ class EventRegistration(models.Model): _description = 'Attendee' _inherit = ['mail.thread'] _order = 'name, create_date desc' + _mail_mass_mailing = _('Event Attendees') origin = fields.Char( string='Source Document', readonly=True, diff --git a/addons/event/models/event_mail.py b/addons/event/models/event_mail.py index 6a5edd12854..a9a1a81db6b 100644 --- a/addons/event/models/event_mail.py +++ b/addons/event/models/event_mail.py @@ -33,7 +33,7 @@ class EventMailScheduler(models.Model): ('after_sub', 'After each registration'), ('before_event', 'Before the event'), ('after_event', 'After the event')], - string='When to Run ', default="before_event", required=True) + string='Trigger ', default="before_event", required=True) template_id = fields.Many2one( 'mail.template', string='Email to Send', domain=[('model', '=', 'event.registration')], required=True, ondelete='restrict', diff --git a/addons/event/views/event_views.xml b/addons/event/views/event_views.xml index 70a9f8049e6..5bb9e12482b 100644 --- a/addons/event/views/event_views.xml +++ b/addons/event/views/event_views.xml @@ -423,28 +423,35 @@ event.mail
- - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + +
diff --git a/addons/website_event_track/models/event_track.py b/addons/website_event_track/models/event_track.py index c7acc2f00a8..7560077da61 100644 --- a/addons/website_event_track/models/event_track.py +++ b/addons/website_event_track/models/event_track.py @@ -32,6 +32,7 @@ class Track(models.Model): _description = 'Event Track' _order = 'priority, date' _inherit = ['mail.thread', 'website.seo.metadata', 'website.published.mixin'] + _mail_mass_mailing = _('Track Speakers') name = fields.Char('Title', required=True, translate=True) active = fields.Boolean(default=True) From ddd4479d10c1071222fec38f89d803c4509013de Mon Sep 17 00:00:00 2001 From: Mitali Patel Date: Thu, 9 Feb 2017 11:16:40 +0100 Subject: [PATCH 4/8] [IMP] event: apply various usability improvements * reporting: remove report.event.registration as it can be replaced by pivot and graph views on event.registration model directly. The custom SQL view does not add any valuable information; * event: correctly take limitations from event category and check minimum seats is lesser or equal to maximum seats; * event: reorganize a bit the form view * avoid some kind of random ordering of buttons; * move seats availability directly in the form view; * ticket page is now used only for ticketing purpose, not a mismatch with seats; * registration: attendees can be set as done only for confirmed events to avoid confusion when working with draft events; Misc usability * event.type: rename event type to event category to have a unified term across various event addons; * event: stop tracking active field as it does not add interesting information; it should not toggle everyday; * event: track location as it does add valuable information; * event: rename some labels to ease user experience; * event.mail: add missing description and rec name; --- addons/event/__manifest__.py | 1 - addons/event/models/event.py | 42 ++++---- addons/event/models/event_mail.py | 2 + addons/event/report/__init__.py | 2 - .../event/report/report_event_registration.py | 71 -------------- .../report/report_event_registration_view.xml | 70 ------------- addons/event/security/event_security.xml | 11 --- addons/event/security/ir.model.access.csv | 1 - addons/event/views/event_views.xml | 97 +++++++++++-------- addons/event_sale/views/event_views.xml | 38 +++----- addons/website_event/views/event_views.xml | 7 +- .../website_event_track/views/event_views.xml | 2 +- 12 files changed, 103 insertions(+), 241 deletions(-) delete mode 100644 addons/event/report/report_event_registration.py delete mode 100644 addons/event/report/report_event_registration_view.xml diff --git a/addons/event/__manifest__.py b/addons/event/__manifest__.py index c7da5440836..153d34dcbae 100644 --- a/addons/event/__manifest__.py +++ b/addons/event/__manifest__.py @@ -23,7 +23,6 @@ Key Features 'security/ir.model.access.csv', 'wizard/event_confirm_view.xml', 'views/event_views.xml', - 'report/report_event_registration_view.xml', 'report/event_event_templates.xml', 'report/event_event_reports.xml', 'data/event_data.xml', diff --git a/addons/event/models/event.py b/addons/event/models/event.py index b50dff53a59..7a4a2496f0b 100644 --- a/addons/event/models/event.py +++ b/addons/event/models/event.py @@ -11,11 +11,10 @@ from dateutil.relativedelta import relativedelta class EventType(models.Model): - """ Event Type """ _name = 'event.type' - _description = 'Event Type' + _description = 'Event Category' - name = fields.Char('Event Type', required=True, translate=True) + name = fields.Char('Event Category', required=True, translate=True) default_reply_to = fields.Char('Reply To') default_registration_min = fields.Integer( 'Default Minimum Registration', default=0, @@ -53,10 +52,11 @@ class EventEvent(models.Model): name = fields.Char( string='Event Name', translate=True, required=True, readonly=False, states={'done': [('readonly', True)]}) - active = fields.Boolean(default=True, track_visibility="onchange") + active = fields.Boolean(default=True) user_id = fields.Many2one( 'res.users', string='Responsible', default=lambda self: self.env.user, + track_visibility="onchange", readonly=False, states={'done': [('readonly', True)]}) company_id = fields.Many2one( 'res.company', string='Company', change_default=True, @@ -64,6 +64,7 @@ class EventEvent(models.Model): required=False, readonly=False, states={'done': [('readonly', True)]}) organizer_id = fields.Many2one( 'res.partner', string='Organizer', + track_visibility="onchange", default=lambda self: self.env.user.company_id.partner_id) event_type_id = fields.Many2one( 'event.type', string='Category', @@ -119,13 +120,15 @@ class EventEvent(models.Model): ('confirm', 'Confirmed'), ('done', 'Done')], string='Status', default='draft', readonly=True, required=True, copy=False, help="If event is created, the status is 'Draft'. If event is confirmed for the particular dates the status is set to 'Confirmed'. If the event is over, the status is set to 'Done'. If event is cancelled the status is set to 'Cancelled'.") - auto_confirm = fields.Boolean(string='Confirmation not required', compute='_compute_auto_confirm') + auto_confirm = fields.Boolean(string='Autoconfirm Registrations', compute='_compute_auto_confirm') reply_to = fields.Char( 'Reply-To Email', readonly=False, states={'done': [('readonly', True)]}, help="The email address of the organizer is likely to be put here, with the effect to be in the 'Reply-To' of the mails sent automatically at event or registrations confirmation. You can also put the email address of your mail gateway if you use one.") address_id = fields.Many2one( - 'res.partner', string='Location', default=lambda self: self.env.user.company_id.partner_id, - readonly=False, states={'done': [('readonly', True)]}) + 'res.partner', string='Location', + default=lambda self: self.env.user.company_id.partner_id, + readonly=False, states={'done': [('readonly', True)]}, + track_visibility="onchange") country_id = fields.Many2one('res.country', 'Country', related='address_id.country_id', store=True) description = fields.Html( string='Description', oldname='note', translate=html_translate, sanitize_attributes=False, @@ -195,12 +198,18 @@ class EventEvent(models.Model): if self.event_type_id: self.seats_min = self.event_type_id.default_registration_min self.seats_max = self.event_type_id.default_registration_max + if self.event_type_id.default_registration_max: + self.seats_availability = 'limited' self.reply_to = self.event_type_id.default_reply_to - @api.one + @api.constrains('seats_min', 'seats_max', 'seats_availability') + def _check_seats_min_max(self): + if any(event.seats_availability == 'limited' and event.seats_min > event.seats_max for event in self): + raise ValidationError(_('Maximum attendees number should be greater than minimum attendees number.')) + @api.constrains('seats_max', 'seats_available') def _check_seats_limit(self): - if self.seats_availability == 'limited' and self.seats_max and self.seats_available < 0: + if any(event.seats_availability == 'limited' and event.seats_max and event.seats_available < 0 for event in self): raise ValidationError(_('No more available seats.')) @api.one @@ -257,15 +266,6 @@ class EventEvent(models.Model): def button_confirm(self): self.state = 'confirm' - @api.multi - def action_event_registration_report(self): - res = self.env['ir.actions.act_window'].for_xml_id('event', 'action_report_event_registration') - res['context'] = { - "search_default_event_id": self.id, - "group_by": ['create_date:day'], - } - return res - @api.one def mail_attendees(self, template_id, force_send=False, filter_func=lambda self: True): for attendee in self.registration_ids.filtered(filter_func): @@ -361,10 +361,12 @@ class EventRegistration(models.Model): def button_reg_close(self): """ Close Registration """ today = fields.Datetime.now() - if self.event_id.date_begin <= today: + if self.event_id.date_begin <= today and self.event_id.state == 'confirm': self.write({'state': 'done', 'date_closed': today}) + elif self.event_id.state == 'draft': + raise UserError(_("You must wait the event confirmation before doing this action.")) else: - raise UserError(_("You must wait for the starting day of the event to do this action.")) + raise UserError(_("You must wait the event starting day before doing this action.")) @api.one def button_reg_cancel(self): diff --git a/addons/event/models/event_mail.py b/addons/event/models/event_mail.py index a9a1a81db6b..c8ba8f8b40d 100644 --- a/addons/event/models/event_mail.py +++ b/addons/event/models/event_mail.py @@ -20,6 +20,8 @@ class EventMailScheduler(models.Model): configuration allowing to send emails on events since Odoo 9. A cron exists that periodically checks for mailing to run. """ _name = 'event.mail' + _rec_name = 'event_id' + _description = 'Event Automated Mailing' event_id = fields.Many2one('event.event', string='Event', required=True, ondelete='cascade') sequence = fields.Integer('Display order') diff --git a/addons/event/report/__init__.py b/addons/event/report/__init__.py index 42c58d25bd9..67dee8c60db 100644 --- a/addons/event/report/__init__.py +++ b/addons/event/report/__init__.py @@ -1,4 +1,2 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. - -import report_event_registration diff --git a/addons/event/report/report_event_registration.py b/addons/event/report/report_event_registration.py deleted file mode 100644 index 14f8f33a95a..00000000000 --- a/addons/event/report/report_event_registration.py +++ /dev/null @@ -1,71 +0,0 @@ -# -*- coding: utf-8 -*- -# Part of Odoo. See LICENSE file for full copyright and licensing details. - -from odoo import api, models, fields -from odoo import tools - - -class ReportEventRegistration(models.Model): - """Events Analysis""" - _name = "report.event.registration" - _order = 'event_date desc' - _auto = False - - create_date = fields.Datetime('Creation Date', readonly=True) - event_date = fields.Datetime('Event Date', readonly=True) - event_id = fields.Many2one('event.event', 'Event', required=True) - draft_state = fields.Integer(' # No of Draft Registrations') - cancel_state = fields.Integer(' # No of Cancelled Registrations') - confirm_state = fields.Integer(' # No of Confirmed Registrations') - seats_max = fields.Integer('Max Seats') - nbevent = fields.Integer('Number of Events') - nbregistration = fields.Integer('Number of Registrations') - event_type_id = fields.Many2one('event.type', 'Event Type') - registration_state = fields.Selection([('draft', 'Draft'), ('confirm', 'Confirmed'), ('done', 'Attended'), ('cancel', 'Cancelled')], 'Registration State', readonly=True, required=True) - event_state = fields.Selection([('draft', 'Draft'), ('confirm', 'Confirmed'), ('done', 'Done'), ('cancel', 'Cancelled')], 'Event State', readonly=True, required=True) - user_id = fields.Many2one('res.users', 'Event Responsible', readonly=True) - name_registration = fields.Char('Participant / Contact Name', readonly=True) - company_id = fields.Many2one('res.company', 'Company', readonly=True) - - @api.model_cr - def init(self): - """Initialize the sql view for the event registration """ - tools.drop_view_if_exists(self.env.cr, 'report_event_registration') - - # TOFIX this request won't select events that have no registration - self.env.cr.execute(""" CREATE VIEW report_event_registration AS ( - SELECT - e.id::varchar || '/' || coalesce(r.id::varchar,'') AS id, - e.id AS event_id, - e.user_id AS user_id, - r.name AS name_registration, - r.create_date AS create_date, - e.company_id AS company_id, - e.date_begin AS event_date, - count(r.id) AS nbevent, - count(r.event_id) AS nbregistration, - CASE WHEN r.state IN ('draft') THEN count(r.event_id) ELSE 0 END AS draft_state, - CASE WHEN r.state IN ('open','done') THEN count(r.event_id) ELSE 0 END AS confirm_state, - CASE WHEN r.state IN ('cancel') THEN count(r.event_id) ELSE 0 END AS cancel_state, - e.event_type_id AS event_type_id, - e.seats_max AS seats_max, - e.state AS event_state, - r.state AS registration_state - FROM - event_event e - LEFT JOIN event_registration r ON (e.id=r.event_id) - - GROUP BY - event_id, - r.id, - registration_state, - event_type_id, - e.id, - e.date_begin, - e.user_id, - event_state, - e.company_id, - e.seats_max, - name_registration - ) - """) diff --git a/addons/event/report/report_event_registration_view.xml b/addons/event/report/report_event_registration_view.xml deleted file mode 100644 index f5579c1b0e7..00000000000 --- a/addons/event/report/report_event_registration_view.xml +++ /dev/null @@ -1,70 +0,0 @@ - - - - - - report.event.registration.pivot - report.event.registration - - - - - - - - - - - report.event.registration.graph - report.event.registration - - - - - - - - - - - - report.event.registration.search - report.event.registration - - - - - - - - - - - - - - - - - - - - - - - - - - - Events Analysis - report.event.registration - form - pivot,graph - - {} - - - - - - diff --git a/addons/event/security/event_security.xml b/addons/event/security/event_security.xml index 6605989b3fc..110262928b6 100644 --- a/addons/event/security/event_security.xml +++ b/addons/event/security/event_security.xml @@ -41,16 +41,5 @@ ] - - Event/Report Registration: multi-company - - - ['|', - ('company_id', '=', False), - ('company_id', 'child_of', [user.company_id.id]), - ] - - - diff --git a/addons/event/security/ir.model.access.csv b/addons/event/security/ir.model.access.csv index ac13c583b55..d17116d26e9 100644 --- a/addons/event/security/ir.model.access.csv +++ b/addons/event/security/ir.model.access.csv @@ -10,4 +10,3 @@ access_event_mail,event.mail,model_event_mail,event.group_event_user,1,0,0,0 access_event_mail_manager,event.mail manager,model_event_mail,event.group_event_manager,1,1,1,1 access_event_mail_registration,event.mail.registration,model_event_mail_registration,event.group_event_user,1,0,0,0 access_event_mail_registration_manager,event.mail.registration.manager,model_event_mail_registration,event.group_event_manager,1,1,1,1 -access_report_event_registration,report.event.registration,model_report_event_registration,event.group_event_user,1,1,1,1 \ No newline at end of file diff --git a/addons/event/views/event_views.xml b/addons/event/views/event_views.xml index 5bb9e12482b..b7ae32f62ad 100644 --- a/addons/event/views/event_views.xml +++ b/addons/event/views/event_views.xml @@ -11,7 +11,7 @@ event.type.form event.type -
+ @@ -28,14 +28,14 @@ event.type.tree event.type - + - Event Types + Event Categories event.type form @@ -54,6 +54,13 @@ + + Events Analysis + event.event + form + pivot,graph + + event.event.form event.event @@ -69,14 +76,16 @@
- @@ -85,43 +94,37 @@
- + + - + + + + - + + + + + - - - - - - - - - - - - - - + @@ -211,8 +214,9 @@ Expected attendees
- Confirmed attendees - (stats) + + Confirmed attendees + @@ -264,12 +268,23 @@
+ + event.event.view.pivot + event.event + + + + + + + + Events ir.actions.act_window event.event form - kanban,calendar,tree,form + kanban,calendar,tree,form,pivot {"search_default_upcoming":1}

@@ -291,6 +306,12 @@ view_type="form"/> + @@ -328,10 +349,10 @@ + - diff --git a/addons/event_sale/views/event_views.xml b/addons/event_sale/views/event_views.xml index 64e2ec9caa4..f706ee317e6 100644 --- a/addons/event_sale/views/event_views.xml +++ b/addons/event_sale/views/event_views.xml @@ -46,29 +46,21 @@ event.event - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + diff --git a/addons/website_event/views/event_views.xml b/addons/website_event/views/event_views.xml index 7273aba2878..61666898621 100644 --- a/addons/website_event/views/event_views.xml +++ b/addons/website_event/views/event_views.xml @@ -6,11 +6,12 @@ event.event - diff --git a/addons/website_event_track/views/event_views.xml b/addons/website_event_track/views/event_views.xml index aaee4c93266..e28d5d13a5b 100644 --- a/addons/website_event_track/views/event_views.xml +++ b/addons/website_event_track/views/event_views.xml @@ -6,7 +6,7 @@ event.event -

- -
From 5d4dd98af2672ccdde37d9587653c80a0ec7c661 Mon Sep 17 00:00:00 2001 From: Mitali Patel Date: Mon, 13 Feb 2017 12:04:21 +0100 Subject: [PATCH 6/8] [IMP] website_event: apply checkout / buy process improvements * reword various texts in website_event to avoid references to a sell or checkout process as website_event does not handle sakes; * if there is only one ticket available, propose to take one by default. Display Register Now instead of Order Now if tickets are free. Display an error if the user chooses no tickets in its registration.; * link in cart for event tickets redirects to event, not product; * confirm attendees only at invoice payment; * improve wording, use schedule instead of agenda. --- .../views/event_config_settings_views.xml | 6 ++--- addons/event_sale/models/__init__.py | 1 + addons/event_sale/models/account_invoice.py | 17 ++++++++++++ addons/event_sale/models/sale_order.py | 6 ++--- .../wizard/event_edit_registration.py | 2 +- addons/website_event/README.md | 2 +- addons/website_event/__manifest__.py | 2 +- .../static/description/index.html | 26 +++++++------------ .../static/src/js/website_event.js | 20 +++++++++----- .../website_event/views/event_templates.xml | 7 ++++- addons/website_event_sale/__manifest__.py | 2 +- .../website_event_sale/models/sale_order.py | 2 +- .../views/event_templates.xml | 24 +++++++++++++++-- .../views/event_track_views.xml | 4 +-- 14 files changed, 83 insertions(+), 38 deletions(-) create mode 100644 addons/event_sale/models/account_invoice.py diff --git a/addons/event/views/event_config_settings_views.xml b/addons/event/views/event_config_settings_views.xml index 6b18bb9d71d..67601b1274d 100644 --- a/addons/event/views/event_config_settings_views.xml +++ b/addons/event/views/event_config_settings_views.xml @@ -24,14 +24,14 @@ -
+
-
diff --git a/addons/event_sale/models/__init__.py b/addons/event_sale/models/__init__.py index 988d9523f9b..a55c87dd5a6 100644 --- a/addons/event_sale/models/__init__.py +++ b/addons/event_sale/models/__init__.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- +import account_invoice import sale_order import product import event diff --git a/addons/event_sale/models/account_invoice.py b/addons/event_sale/models/account_invoice.py new file mode 100644 index 00000000000..b8f4e309bb4 --- /dev/null +++ b/addons/event_sale/models/account_invoice.py @@ -0,0 +1,17 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import api, models + + +class AccountInvoice(models.Model): + _inherit = 'account.invoice' + + @api.multi + def action_invoice_paid(self): + """ When an invoice linked to a sales order selling registrations is + paid confirm attendees. Attendees should indeed not be confirmed before + full payment. """ + res = super(AccountInvoice, self).action_invoice_paid() + self.mapped('invoice_line_ids.sale_line_ids')._update_registrations(confirm=True) + return res diff --git a/addons/event_sale/models/sale_order.py b/addons/event_sale/models/sale_order.py index d917254fb34..ec9bbe2ffae 100644 --- a/addons/event_sale/models/sale_order.py +++ b/addons/event_sale/models/sale_order.py @@ -10,7 +10,7 @@ class SaleOrder(models.Model): def action_confirm(self): self.ensure_one() res = super(SaleOrder, self).action_confirm() - self.order_line._update_registrations(confirm=True) + self.order_line._update_registrations(confirm=False, cancel_to_draft=False) if any(self.order_line.filtered(lambda line: line.event_id)): return self.env['ir.actions.act_window'].with_context(default_sale_order_id=self.id).for_xml_id('event_sale', 'action_sale_order_event_registration') return res @@ -35,7 +35,7 @@ class SaleOrderLine(models.Model): return res @api.multi - def _update_registrations(self, confirm=True, registration_data=None): + def _update_registrations(self, confirm=True, cancel_to_draft=False, registration_data=None): """ 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 @@ -46,7 +46,7 @@ class SaleOrderLine(models.Model): existing_registrations = registrations.filtered(lambda self: self.sale_order_line_id.id == so_line.id) if confirm: existing_registrations.filtered(lambda self: self.state != 'open').confirm_registration() - else: + if cancel_to_draft: existing_registrations.filtered(lambda self: self.state == 'cancel').do_draft() for count in range(int(so_line.product_uom_qty) - len(existing_registrations)): diff --git a/addons/event_sale/wizard/event_edit_registration.py b/addons/event_sale/wizard/event_edit_registration.py index 0ae579bc693..f03623d91ad 100644 --- a/addons/event_sale/wizard/event_edit_registration.py +++ b/addons/event_sale/wizard/event_edit_registration.py @@ -55,7 +55,7 @@ class RegistrationEditor(models.TransientModel): self.env['event.registration'].create(values) if self.env.context.get('active_model') == 'sale.order': for order in self.env['sale.order'].browse(self.env.context.get('active_ids', [])): - order.order_line._update_registrations(confirm=True) + order.order_line._update_registrations(confirm=False) return {'type': 'ir.actions.act_window_close'} diff --git a/addons/website_event/README.md b/addons/website_event/README.md index 862c44a685c..e4691d2619b 100644 --- a/addons/website_event/README.md +++ b/addons/website_event/README.md @@ -10,7 +10,7 @@ Create Awesome Event Pages ### Get rid of old WYSIWYG editors -Create beautiful event pages by drag & droping well designed *'Building Blocks'*. Publish event photos, speakers, agenda, etc. +Create beautiful event pages by drag & droping well designed *'Building Blocks'*. Publish event photos, speakers, schedule, etc. Odoo's unique *'edit inline'* approach makes website creation surprisingly easy. "Want to introduce a speaker? to change the price of a ticket? to update a banner? promote sponsors?" just click and change. diff --git a/addons/website_event/__manifest__.py b/addons/website_event/__manifest__.py index bd467c9b02a..6811d586e16 100644 --- a/addons/website_event/__manifest__.py +++ b/addons/website_event/__manifest__.py @@ -4,7 +4,7 @@ 'name': 'Online Events', 'category': 'Marketing', 'sequence': 135, - 'summary': 'Schedule, Promote and Sell Events', + 'summary': 'Publish Events and Manage Online Registrations on your Website', 'website': 'https://www.odoo.com/page/website-builder', 'description': """ Online Events diff --git a/addons/website_event/static/description/index.html b/addons/website_event/static/description/index.html index 8ef92f0377c..5648a814172 100644 --- a/addons/website_event/static/description/index.html +++ b/addons/website_event/static/description/index.html @@ -1,7 +1,7 @@

Create your own events

-

Organize, publish, promote and sell.

+

Organize, publish and promote.

@@ -15,7 +15,7 @@

Host events that resonates with your audience

Easily create live or online events

- One platform to manage it all. Odoo Events covers all aspects of an event manager's work: organization, visibility, promotion and sale. Use it with any kind of event, including conferences, meetings, seminars, training and webinars. + One platform to manage it all. Odoo Events covers all aspects of an event manager's work: organization, visibility, promotion. Use it with any kind of event, including conferences, meetings, seminars, training and webinars.

@@ -51,7 +51,7 @@
-

Automatically display your event's agenda in a clear, classy design on your website.

+

Automatically display your event's schedule in a clear, classy design on your website.

@@ -69,9 +69,9 @@

Get sponsors to come to you

-

Sell sponsorship, promote your sponsors

+

Promote your sponsors

- Easily manage existing and new sponsors with Odoo Events. Add sponsors to your events and publish sponsors per level (e.g., gold) on the bottom of every page of the event. Sell sponsorship packages online through Odoo eCommerce.

+ Easily manage existing and new sponsors with Odoo Events. Add sponsors to your events and publish sponsors per level (e.g., gold) on the bottom of every page of the event.

@@ -83,22 +83,16 @@
-
+
+

Total promotion tools

+

Promote events efficiently on all channels

- -

Total promotion tools

-

Promote events efficiently on all channels

-

- Segment your audience, leverage social media and email marketing to promote your events to the right audience. Odoo Events' smooth integration with countless Odoo apps simplifies promotion to the extreme. Setup automated campaigns for attendees, or automatically send timely emails to registrants. Optimize conversions with ad-hoc landing pages for your different marketing campaigns. -

+
- -

Sell tickets online

-

Automate the registration and payment process

- Manage registrations and sell tickets online to your events. Choose whether it is a free event or whether attendees need to register for a fee. Pick the paying method -pay online with a credit card or with the invoice. Define special conditions such as early-bird prices, member benefits or extra services with multiple tickets. All you need to boost your event attendance. + Segment your audience, leverage social media and email marketing to promote your events to the right audience. Odoo Events' smooth integration with countless Odoo apps simplifies promotion to the extreme. Setup automated campaigns for attendees, or automatically send timely emails to registrants. Optimize conversions with ad-hoc landing pages for your different marketing campaigns.

diff --git a/addons/website_event/static/src/js/website_event.js b/addons/website_event/static/src/js/website_event.js index cb531d0035a..2df7642c1a3 100644 --- a/addons/website_event/static/src/js/website_event.js +++ b/addons/website_event/static/src/js/website_event.js @@ -26,13 +26,21 @@ var EventRegistrationForm = Widget.extend({ $("#registration_form select").each(function() { post[$(this).attr('name')] = $(this).val(); }); - return ajax.jsonRpc($form.attr('action'), 'call', post).then(function (modal) { - var $modal = $(modal); - $modal.appendTo($form).modal(); - $modal.on('click', '.js_goto_event', function () { - $modal.modal('hide'); + var tickets_ordered = _.some(_.map(post, function(value, key) { return parseInt(value) })); + if (! tickets_ordered) { + return $('#registration_form table').after( + '
Please select at least one ticket.
' + ); + } + else { + return ajax.jsonRpc($form.attr('action'), 'call', post).then(function (modal) { + var $modal = $(modal); + $modal.appendTo($form).modal(); + $modal.on('click', '.js_goto_event', function () { + $modal.modal('hide'); + }); }); - }); + } }, }); diff --git a/addons/website_event/views/event_templates.xml b/addons/website_event/views/event_templates.xml index ea714ef45b5..a06e81e5ccb 100644 --- a/addons/website_event/views/event_templates.xml +++ b/addons/website_event/views/event_templates.xml @@ -438,7 +438,12 @@ Sold Out diff --git a/addons/website_event_sale/__manifest__.py b/addons/website_event_sale/__manifest__.py index 4311b952800..67beb8a1d41 100644 --- a/addons/website_event_sale/__manifest__.py +++ b/addons/website_event_sale/__manifest__.py @@ -3,7 +3,7 @@ { 'name': "Online Event's Tickets", 'category': 'Marketing', - 'summary': "Sell Your Event's Tickets", + 'summary': "Manage Events and Sell Tickets Online", 'website': 'https://www.odoo.com/page/events', 'description': """ Online Event's Tickets diff --git a/addons/website_event_sale/models/sale_order.py b/addons/website_event_sale/models/sale_order.py index edfb30e7e62..3cf2d253182 100644 --- a/addons/website_event_sale/models/sale_order.py +++ b/addons/website_event_sale/models/sale_order.py @@ -92,7 +92,7 @@ class SaleOrder(models.Model): # adding attendees elif ticket and new_qty > old_qty: line = OrderLine.browse(values['line_id']) - line._update_registrations(confirm=False, registration_data=kwargs.get('registration_data', [])) + line._update_registrations(confirm=False, cancel_to_draft=True, registration_data=kwargs.get('registration_data', [])) # add in return values the registrations, to display them on website (or not) values['attendee_ids'] = self.env['event.registration'].search([('sale_order_line_id', '=', line.id), ('state', '!=', 'cancel')]).ids return values diff --git a/addons/website_event_sale/views/event_templates.xml b/addons/website_event_sale/views/event_templates.xml index d0005892fd6..adcacf2ccb9 100644 --- a/addons/website_event_sale/views/event_templates.xml +++ b/addons/website_event_sale/views/event_templates.xml @@ -25,6 +25,7 @@ + @@ -74,7 +75,12 @@ - Sold Out @@ -84,8 +90,16 @@ + + class="btn btn-primary btn-lg pull-right a-submit" t-attf-id="#{event.id}"> + + Order Now + + + Register Now + + event.event_ticket_ids @@ -93,6 +107,12 @@