SlideShare a Scribd company logo
Let us recode everything from scratch. Or not.
EXPERIENCE
2018
• Software Engineer, RD Dummies Team Leader
The use case:
— Classy Cool Dev
Thanks Classy Cool Dev!
● Mixin class: extracts transversal features
● AbstractModel: no table, only for definition
● offer features through inheritance
● e.g. messaging mechanism, customer satisfaction request, ...
class MailThread(models.AbstractModel):
_name = 'mail.thread'
_description = 'Mail Thread Mixin'
message_ids = fields.One2many('mail.message', 'Messages')
message_follower_ids = fields.One2many('mail.followers', 'Followers')
def message_post(self, body):
# do stuff
def message_subscribe(self, partners):
# do stuff
● Mixin class: extracts transversal features
● Inheritance: “copy” fields on child
class MailThread(models.AbstractModel):
_name = 'mail.thread'
message_ids = fields.One2many(...)
message_follower_ids = fields.One2many(...)
class Plant(models.Model):
_inherit = ['mail.thread']
name = fields.Char('Plant Name')
class Order(models.Model):
_inherit = ['mail.thread']
name = fields.Char('Reference')
● Mixin class: extracts transversal features
● Inheritance: “copy” fields on child
class MailThread(models.AbstractModel):
_name = 'mail.thread'
message_ids = fields.One2many(...)
message_follower_ids = fields.One2many(...)
class Plant(models.Model):
_inherit = ['mail.thread']
name = fields.Char('Plant Name')
message_ids = fields.One2many(...)
message_follower_ids = fields.One2many(...)
class Order(models.Model):
_inherit = ['mail.thread']
name = fields.Char('Reference')
message_ids = fields.One2many(...)
message_follower_ids = fields.One2many(...)
● Mixin class: extracts transversal features
● Inheritance: class inheritance: methods, super(), ...
class MailThread(models.AbstractModel):
_name = 'mail.thread'
message_ids = fields.One2many(...)
message_follower_ids = fields.One2many(...)
def message_post(self, body):
# do stuff
return message
class Plant(models.Model):
_name = 'nursery.plant'
_inherit = ['mail.thread']
name = fields.Char('Plant Name')
price = fields.Integer('Plant Price')
def say_hello(self):
self.message_post('Hello')
def message_post(self, body):
if self.message_ids: ...
self.message_follower_ids.write({})
return super()
● Mixin class: extracts transversal features
● Inherit abstract class itself (Since 11.0)
○ tweaking abstract through inheritance applies to all childs
class MyOwnMailThread(models.AbstractModel):
_name = 'mail.thread'
_inherit = 'mail.thread'
message_my_own = fields.Integer(...)
def message_my_own_stuff(self):
...
return
def message_post(self, body):
# do more stuff
self.message_my_own_stuff()
return super()
I master mixins.
Complexity
Power0
3
1 2 3
2
1
Complexity
Power0
3
1 2 3
2
1
● Communication & Organization
○ Discuss on a document, send mailings
○ Schedule activities
● Marketing
○ Get customer satisfaction insights
○ Track campaigns and mediums
● Website
○ Manage document publication
○ Promote pages
● Communication & Organization
○ Discuss on a document, send mailings
○ Schedule activities
● Marketing
○ Get customer satisfaction insights
○ Track campaigns and mediums
● Website
○ Manage document publication
○ Promote pages
● mail.thread
● mail.activity.mixin
● rating.mixin
● utm.mixin
● portal, website.published
● website.seo.metadata
● Features of mixins
● How to implement them
● Code bits
● Live result
● Documentation ?
○ Odoo code
○ Documentation
○ https://github.com/tivisse/odoodays-2018
● Add messaging to any class
● Auto-interfacing with e-mail
● How to use:
○ inherit mail.thread
○ add widgets
○ have fun !
● Add messaging to any class
● Auto-interfacing with e-mail
● How to use:
○ Inherit mail.thread
○ Add widgets
○ Have fun !
class Plant(models.Model):
_name = 'nursery.plant'
_description = 'Plant'
_inherit = ['mail.thread']
<div class="oe_chatter">
<field name="message_follower_ids"
widget="mail_followers"/>
<field name="message_ids"
widget="mail_thread"/>
</div>
{
'name': Plant Nursery,
'depends': ['mail'],
}
● Messages linked to a document class Message(models.Model):
_name = 'mail.message'
_description = 'Message'
model = fields.Char(...)
res_id = fields.Integer(...)
notified_partner_ids = fields.Many2Many(...)
def create(self, values):
msg = super()
msg._notify()
return msg
def _notify(self):
followers = self.get_followers()
followers.notify()
followers.send_mail()
class Plant(models.Model):
_inherit = ['mail.thread']
# coming from mail.thread inheritance
message_ids = fields.One2many(...)
● Messages linked to a document
● Communication through Chatter
class MailThread(models.AbstractModel):
_name = 'mail.thread'
message_ids = fields.One2many(...)
def message_post(self, subject, body, **kw):
self.env['mail.message'].create({
'model': self.model,
'res_id': self.res_id})
class Plant(models.Model):
_name = 'nursery.plant'
_inherit = ['mail.thread']
def message_post(self, subject, body, **kw):
super()
● Messages linked to a document
● Communication through Chatter
● Followers management
class MailThread(models.AbstractModel):
_name = 'mail.thread'
message_follower_ids = fields.One2many(...)
def message_subscribe(self, partners, channels):
# add followers and listeners
Follower.create(partners)
class Plant(models.Model):
_name = 'nursery.plant'
_inherit = ['mail.thread']
def message_subscribe(self, partners, channels):
super()
● Process and route incoming emails
● Ensure thread detection
● App-specific behavior on new thread
or on update
class MailThread(models.AbstractModel):
_name = 'mail.thread'
def message_process(self, email):
# process email values
def message_route(self, message):
# heuristics when incoming email detected
class Plant(models.Model):
_name = 'nursery.plant'
_inherit = ['mail.thread']
def message_new(self, message):
# do sthg when creating from email
super()
def message_update(self, message):
# do sthg when incoming email
super()
● Activities management on
document
● Interfacing with Chatter
● How to use:
○ inherit mail.activity.mixin
○ add widgets
○ have much fun !
class Plant(models.Model):
_name = 'nursery.plant'
_description = 'Plant'
_inherit = ['mail.thread', 'mail.activity.mixin']
<div class="oe_chatter">
<field name="message_ids" widget="mail_thread"/>
<field name="activity_ids" widget="mail_activity"/>
</div>
{
'name': Plant Nursery,
'depends': ['mail'],
}
● Activities management on
document
● Activity-based state
● Filters
class Plant(models.Model):
_name = 'nursery.plant'
_description = 'Plant'
_inherit = ['mail.thread', 'mail.activity.mixin']
# coming from mail.activity inheritance
activity_ids = fields.One2many('mail.activity')
activity_state = fields.Selection([
('overdue', 'Overdue'),
('today', 'Today'),
('planned', 'Planned')])
● Automatic activity
(re)scheduling or closing
● Specify a responsible on a
given business flow
class MailActivityMixin(models.AbstractModel):
_name = 'mail.activity.mixin'
def activity_schedule(self, type, date):
# Schedule an activity
def activity_feedback(self, feedback):
# Set activities as done
def activity_unlink(self):
# Delete activities
class Order(models.Model):
_name = 'nursery.order'
_inherit = ['mail.thread', 'mail.activity.mixin']
def create(self, vals):
res = super()
res.activity_schedule()
● Automatic activity
(re)scheduling or closing
● Specify a responsible on a
given business flow
class Order(models.Model):
_name = 'nursery.order'
_inherit = ['mail.thread', 'mail.activity.mixin']
@api.model
def create(self, vals):
res = super(Order, self).create(vals)
res.activity_schedule(
'mail.mail_activity_data_todo',
user_id=self.env.ref('base.user_demo').id,
date_deadline=fields.Date.today() + relativedelta(days=1),
summary=_('Pack the order'))
return res
def action_confirm(self):
if self.state != 'draft':
return
self.activity_feedback(['mail.mail_activity_data_todo'])
return self.write({
'state': 'open',
'date_open': fields.Datetime.now(),
})
Complexity
Power0
3
1 2 3
2
1
'mail.activity.mixin'
'mail.thread'
● Add rating on any class
● Request rating via
email/route
● Analyse your ratings
● How to use:
○ It’s a bit of work
class Plant(models.Model):
_name = 'nursery.plant'
_description = 'Plant'
_inherit = ['mail.thread', 'rating.mixin']
{
'name': Plant Nursery,
'depends': ['rating']
}
class RatingMixin(models.AbstractModel):
_name = 'rating.mixin'
rating_ids = fields.One2many('rating.rating', ...)
rating_last_value = fields.Float(...)
rating_last_feedback = fields.Text(...)
rating_count = fields.Integer(...)
● Rated partner (user_id.partner_id field)
○ rating_get_rated_partner_id
○ In our case, nothing to do
class RatingMixin(models.AbstractModel):
_name = 'rating.mixin'
def rating_get_rated_partner_id(self):
if hasattr(self, 'user_id') and self.user_id.partner_id:
return self.user_id.partner_id
return self.env['res.partner']
● Rated partner (user_id.partner_id field)
○ rating_get_rated_partner_id
● Customer (partner_id field)
○ rating_get_partner_id
○ Need to override
class RatingMixin(models.AbstractModel):
_name = 'rating.mixin'
def rating_get_partner_id(self):
if self.customer_id.partner_id:
return self.customer_id.partner_id
return self.env['res.partner']
class Customer(models.Model):
_name = 'nursery.customer'
partner_id = fields.Many2one('res.partner')
class Order(models.Model):
_name = 'nursery.order'
def rating_get_partner_id(self):
if self.customer_id.partner_id:
return self.customer_id.partner_id
return self.env['res.partner']
● Rated partner (user_id.partner_id field)
○ rating_get_rated_partner_id
● Customer (partner_id field)
○ rating_get_partner_id
● Access token
○ rating_get_access_token
● Rated partner (user_id.partner_id field)
○ rating_get_rated_partner_id
● Customer (partner_id field)
○ rating_get_partner_id
● Access token
○ rating_get_access_token
● Routes (/rating/<token>/<score>)
● Rated partner (user_id.partner_id field)
○ rating_get_rated_partner_id
● Customer (partner_id field)
○ rating_get_partner_id
● Access token
○ rating_get_access_token
● Routes (/rating/<token>/<score>)
● Email Template using this data
● Email Template using this data
<record id="mail_template_plant_order_rating" model="mail.template">
<field name="name">Plant: Rating Request</field>
<field name="email_from">${(object.rating_get_rated_partner_id().email or '') | safe}</field>
<field name="subject">${object.name}: Service Rating Request</field>
<field name="model_id" ref="plant_nursery.model_nursery_order"/>
<field name="partner_to" >${object.rating_get_partner_id().id}</field>
<field name="auto_delete" eval="True"/>
<field name="body_html" type="html">
<div>
% set access_token = object.rating_get_access_token()
<!-- Insert Beautiful Email Stuff -->
<table>
<tr>
<td><a href="/rating/${access_token}/10"><img src="satisfied.png"/></a></td>
<td><a href="/rating/${access_token}/5"><img src="not_satisfied.png"/></a></td>
<td><a href="/rating/${access_token}/1"><img src="highly_not_satisfied.png"/></a></td>
</tr>
</table>
<!-- Insert Ending Beautiful Email Stuff -->
</div>
</field>
</record>
● Track incoming visitors
● Pre-built with three fields:
campaign, source, medium
● Simple to extend
class Plant(models.Model):
_name = 'nursery.plant'
_description = 'Plant'
_inherit = ['utm.mixin']
class UtmMixin(models.AbstractModel):
_name = 'utm.mixin'
campaign_id = fields.Many2one('utm.campaign')
source_id = fields.Many2one('utm.source')
medium_id = fields.Many2one('utm.medium')
{
'name': Plant Nursery,
'depends': ['utm'],
}
● Track incoming visitors
● Pre-built with three fields:
campaign, source, medium
● Simple to extend
● URL parsing
class Plant(models.Model):
_name = 'nursery.plant'
_description = 'Plant'
_inherit = ['utm.mixin']
http://127.0.0.1:8069/plants?utm_campaign=sale&utm_medium=facebook&utm_source=facebook_ad
s
Complexity
Power0
3
1 2 3
2
1
'rating.mixin'
'mail.activity.mixin''Utm.mixin'
'mail.thread'
● ‘Optimize’ SE rankings
● Add fields
○ Page title
○ Keywords
○ Description
class Plant(models.Model):
_name = 'nursery.plant'
_description = 'Plant'
_inherit = ['website.seo.metadata']
{
'name': Plant Nursery,
'depends': ['website'],
}
class SeoMetadata(models.AbstractModel):
_name = 'website.seo.metadata'
website_meta_title = fields.Char('')
website_meta_description = fields.Text('')
website_meta_keywords = fields.Char('')
website_meta_og_img = fields.Char('')
● ‘main_object’ magic in website
● Website promote button
● Set SEO metadata
@route('/plant/<model("nursery.plant"):plant>/',
type='http', auth='public, website=True)
def plant(self, plant, **post):
values = {
'main_object': plant,
'plant': plant,
'stuff': post.get('stuff', 'brol'),
}
return request.render("plant_page", values)
● ‘main_object’ magic in website
● Website promote button
● Set SEO metadata
@route('/plant/<model("nursery.plant"):plant>/',
type='http', auth='public, website=True)
def plant(self, plant, **post):
values = {
'main_object': plant,
'plant': plant,
'stuff': post.get('stuff', 'brol'),
}
return request.render("plant_page", values)
● Control visibility of documents
● Add fields
○ published
○ URL (slug)
● Access rights & route
management still up to you !
class Plant(models.Model):
_name = 'nursery.plant'
_description = 'Plant'
_inherit = ['website.published.mixin']
{
'name': Plant Nursery,
'depends': ['website'],
}
class WebsitePublishedMixin(models.AbstractModel):
_name = "website.published.mixin"
website_published = fields.Boolean('')
website_url = fields.Char(compute='_compute_website_url')
@api.multi
def _compute_website_url(self):
for record in self:
record.website_url = '#'
● Control visibility of documents
● Wesite URL: computed field
○ -> slug (/plant/tree-1)
● Backend: use website_button
○ -> jump to website_url
<button class="oe_stat_button"
name="website_publish_button"
type="object" icon="fa-globe">
<field name="website_published"
widget="website_button"/>
</button>
from odoo.addons.http_routing.models.ir_http import slug
class Plant(models.Model):
_name = 'nursery.plant'
_inherit = ['website.published.mixin']
def _compute_website_url(self):
for plant in self:
plant.website_url = '/plant/%s' % slug(plant)
● publish_management widget
● Link backend / frontend
○ Give action to execute
<t t-call="website.publish_management">
<t t-set="object" t-value="plant"/>
<t t-set="publish_edit" t-value="True"/>
<t t-set="action"
t-value="'plant_nursery.action_nursery_plant"/>
</t>
● Restrict document to a specific
website
● Add website_id
● Add a method to be used in
routes
class Plant(models.Model):
_name = 'nursery.plant'
_description = 'Plant'
_inherit = ['website.multi.mixin']
{
'name': Plant Nursery,
'depends': ['website'],
}
class WebsiteMultiMixin(models.AbstractModel):
_name = 'website.multi.mixin'
website_id = fields.Many2one('website')
@api.multi
def can_access_from_current_website(self, website_id=False):
# Specify if the record can be accessed on this website
● Publish document on a specific
website
● Add website_id
● Add a method
_compute_website_published
class Plant(models.Model):
_name = 'nursery.plant'
_description = 'Plant'
_inherit = ['website.published.multi.mixin']
{
'name': Plant Nursery,
'depends': ['website'],
}
class WebsitePublishedMultiMixin(models.AbstractModel):
_name = 'website.published.multi.mixin'
website_id = fields.Many2one('website')
website_published = fields.Boolean(compute='_compute_website_published')
def _compute_website_published(self):
# Specify if the record is published on this website
● Document - and App- specific
portal url computation
class Plant(models.Model):
_name = 'nursery.plant'
_description = 'Plant'
_inherit = ['portal.mixin']
{
'name': Plant Nursery,
'depends': ['portal'],
}
● Document - and App- specific
portal url computation
● Generic URL computation
○ /mail/view controller
○ access_token
○ partner_id
○ integration with auth_signup
class PortalMixin(models.AbstractModel):
_name = "portal.mixin"
access_url = fields.Char(compute='_compute_access_url')
access_token = fields.Char('Security Token')
access_warning = fields.Text(compute="_compute_access_warning")
def _compute_access_warning(self):
# Set a warning text if the record can't be shared
access_warning = ''
def _compute_access_url(self):
# Set the URL to reach the record on portal
record.access_url = '#'
● Document - and App- specific
portal url computation
● In your App
○ Portal Implementation...
○ access_token definition
○ Share button
● /mail/view controller check and
redirection to portal
class PortalMixin(models.AbstractModel):
_name = "portal.mixin"
access_url = fields.Char(compute='_compute_access_url')
access_token = fields.Char('Security Token')
access_warning = fields.Text(compute="_compute_access_warning")
def _compute_access_warning(self):
# Set a warning text if the record can't be shared
access_warning = ''
def _compute_access_url(self):
# Set the URL to reach the record on portal
record.access_url = '#'
<header>
<button name="%(portal.portal_share_action)d" string="Share"
type="action" class="oe_highlight oe_read_only"/>
</header>
Complexity
Power0
3
1 2 3
2
1
'rating.mixin'
'portal.mixin'
'mail.activity.mixin'
'website.seo.metadata'
'utm.mixin'
'website.published'
'website.multi'
'website.published.multi'
'mail.thread'
— Still Classy Cool Dev
● Characterize / filter messages
● Subtype definition (XML)
○ model specific (e.g. plant)
○ default / hidden
● Use in code: message_post
class Plant(models.Model):
_name = 'nursery.plant'
_inherit = ['mail.thread']
def write(self, values)::
res = super()
if 'price' in values:
self.message_post('Price Updated', subtype='plant_price')
return res
<record id="plant_price" model="mail.message.subtype">
<field name="name">Price Updated</field>
<field name="res_model">nursery.plant</field>
<field name="default" eval="True"/>
<field name="hidden" eval="False"/>
<field name="description">Price Updated</field>
</record>
● Track value change
● track_visibility on field
○ onchange
○ Always
○ True
● Automatic logging
class Plant(models.Model):
_name = 'nursery.plant'
_inherit = ['mail.thread']
price = fields.Float('Price', track_visibility=True)
● Warn on some specific value
change
● Link a set of tracking and a
subtype
○ _track_subtype
○ return xml_id
● Message with tracking generated
with the subtype
○ allow people to be notified
class Plant(models.Model):
_name = 'nursery.plant'
_inherit = ['mail.thread', 'rating.mixin']
price = fields.Float('Price',
track_visibility='onchange')
def _track_subtype(self, values):
if 'price' in values:
return 'plant_nursery.plant_price'
return super()
class Plant(models.Model):
_name = 'nursery.plant'
_inherit = ['mail.thread', 'rating.mixin']
price = fields.Float('Price',
track_visibility='onchange')
def _track_template(self, values):
res = super()
if 'price' in values:
res['price'] = (
'plant_price_template',
options)
return res
● Email on some specific value change
● Link a set of tracking and an
automatic mailing
○ _track_template
○ give a mail.template and options
● Template rendered and sent
○ Force mailing to people
● Ultra power: add rating in template
● Email integrated with mailgateway
● Purpose: create / update thread in a
given model
● Owner: record defining the alias
● Example
○ alias on category
○ creating XMas quote
class MailAlias(models.AbstractModel):
_name = 'mail.alias'
name = fields.Char('Email')
# record creation / update
model = fields.Char('Model')
thread_id = fields.Integer('Update specific record')
# record owner
parent_model = fields.Char('Owner model')
parent_thread_id = fields.Integer('Owner ID')
● mail.alias.mixin
● add alias_id field
● Specify what do do with alias by
overriding methods
class Category(models.Model):
_name = 'plant.category'
_inherit = ['mail.alias.mixin']
def get_alias_model_name(self, values):
return 'nursery.order'
def get_alias_values(self):
values = super()
values['alias_defaults'] = {}
return values
class MailAlias(models.AbstractModel):
_name = 'mail.alias.mixin'
_inherit = {'mail.alias' : 'alias_id'}
alias_id = fields.Many2one('Alias')
Complexity
Power0
3
1 2 3
2
1
'mail.alias.mixin'
'rating.mixin'
'portal.mixin'
'mail.activity.mixin'
'website.seo.metadata'
'utm.mixin'
'website.published'
'website.multi'
'website.published.multi'
'mail.thread'
#odooexperience
Based on work from Thibault DELAVALLEE and Martin TRIGAUX, that was based on work from Damien BOUVY
https://github.com/tivisse/odoodays-2018
EXPERIENCE
2018

More Related Content

What's hot

Owl: The New Odoo UI Framework
Owl: The New Odoo UI FrameworkOwl: The New Odoo UI Framework
Owl: The New Odoo UI Framework
Odoo
 
Odoo - From v7 to v8: the new api
Odoo - From v7 to v8: the new apiOdoo - From v7 to v8: the new api
Odoo - From v7 to v8: the new api
Odoo
 
Odoo Experience 2018 - Develop an App with the Odoo Framework
Odoo Experience 2018 - Develop an App with the Odoo FrameworkOdoo Experience 2018 - Develop an App with the Odoo Framework
Odoo Experience 2018 - Develop an App with the Odoo Framework
ElínAnna Jónasdóttir
 
Odoo Website - How to Develop Building Blocks
Odoo Website - How to Develop Building BlocksOdoo Website - How to Develop Building Blocks
Odoo Website - How to Develop Building Blocks
Odoo
 
Common Performance Pitfalls in Odoo apps
Common Performance Pitfalls in Odoo appsCommon Performance Pitfalls in Odoo apps
Common Performance Pitfalls in Odoo apps
Odoo
 
Improving the performance of Odoo deployments
Improving the performance of Odoo deploymentsImproving the performance of Odoo deployments
Improving the performance of Odoo deployments
Odoo
 
Tutorial: Develop an App with the Odoo Framework
Tutorial: Develop an App with the Odoo FrameworkTutorial: Develop an App with the Odoo Framework
Tutorial: Develop an App with the Odoo Framework
Odoo
 
Deploying & Scaling your Odoo Server
Deploying & Scaling your Odoo ServerDeploying & Scaling your Odoo Server
Deploying & Scaling your Odoo Server
Odoo
 
Odoo Online platform: architecture and challenges
Odoo Online platform: architecture and challengesOdoo Online platform: architecture and challenges
Odoo Online platform: architecture and challenges
Odoo
 
Tools for Solving Performance Issues
Tools for Solving Performance IssuesTools for Solving Performance Issues
Tools for Solving Performance Issues
Odoo
 
Impact of the New ORM on Your Modules
Impact of the New ORM on Your ModulesImpact of the New ORM on Your Modules
Impact of the New ORM on Your Modules
Odoo
 
Odoo Performance Limits
Odoo Performance LimitsOdoo Performance Limits
Odoo Performance Limits
Odoo
 
Developing New Widgets for your Views in Owl
Developing New Widgets for your Views in OwlDeveloping New Widgets for your Views in Owl
Developing New Widgets for your Views in Owl
Odoo
 
Best Practices in Handling Performance Issues
Best Practices in Handling Performance IssuesBest Practices in Handling Performance Issues
Best Practices in Handling Performance Issues
Odoo
 
How to Develop your own in App-Purchase Service in Odoo
How to Develop your own in App-Purchase Service in OdooHow to Develop your own in App-Purchase Service in Odoo
How to Develop your own in App-Purchase Service in Odoo
Odoo
 
Odoo - Backend modules in v8
Odoo - Backend modules in v8Odoo - Backend modules in v8
Odoo - Backend modules in v8
Odoo
 
Tips on how to improve the performance of your custom modules for high volume...
Tips on how to improve the performance of your custom modules for high volume...Tips on how to improve the performance of your custom modules for high volume...
Tips on how to improve the performance of your custom modules for high volume...Odoo
 
Introduction to django
Introduction to djangoIntroduction to django
Introduction to djangoIlian Iliev
 
Odoo ORM Methods | Object Relational Mapping in Odoo15
Odoo ORM Methods | Object Relational Mapping in Odoo15 Odoo ORM Methods | Object Relational Mapping in Odoo15
Odoo ORM Methods | Object Relational Mapping in Odoo15
Celine George
 
Deploying Moodle With High Availability and auto-scale on Microsoft Azure pla...
Deploying Moodle With High Availability and auto-scale on Microsoft Azure pla...Deploying Moodle With High Availability and auto-scale on Microsoft Azure pla...
Deploying Moodle With High Availability and auto-scale on Microsoft Azure pla...
Somaroy Gabbita
 

What's hot (20)

Owl: The New Odoo UI Framework
Owl: The New Odoo UI FrameworkOwl: The New Odoo UI Framework
Owl: The New Odoo UI Framework
 
Odoo - From v7 to v8: the new api
Odoo - From v7 to v8: the new apiOdoo - From v7 to v8: the new api
Odoo - From v7 to v8: the new api
 
Odoo Experience 2018 - Develop an App with the Odoo Framework
Odoo Experience 2018 - Develop an App with the Odoo FrameworkOdoo Experience 2018 - Develop an App with the Odoo Framework
Odoo Experience 2018 - Develop an App with the Odoo Framework
 
Odoo Website - How to Develop Building Blocks
Odoo Website - How to Develop Building BlocksOdoo Website - How to Develop Building Blocks
Odoo Website - How to Develop Building Blocks
 
Common Performance Pitfalls in Odoo apps
Common Performance Pitfalls in Odoo appsCommon Performance Pitfalls in Odoo apps
Common Performance Pitfalls in Odoo apps
 
Improving the performance of Odoo deployments
Improving the performance of Odoo deploymentsImproving the performance of Odoo deployments
Improving the performance of Odoo deployments
 
Tutorial: Develop an App with the Odoo Framework
Tutorial: Develop an App with the Odoo FrameworkTutorial: Develop an App with the Odoo Framework
Tutorial: Develop an App with the Odoo Framework
 
Deploying & Scaling your Odoo Server
Deploying & Scaling your Odoo ServerDeploying & Scaling your Odoo Server
Deploying & Scaling your Odoo Server
 
Odoo Online platform: architecture and challenges
Odoo Online platform: architecture and challengesOdoo Online platform: architecture and challenges
Odoo Online platform: architecture and challenges
 
Tools for Solving Performance Issues
Tools for Solving Performance IssuesTools for Solving Performance Issues
Tools for Solving Performance Issues
 
Impact of the New ORM on Your Modules
Impact of the New ORM on Your ModulesImpact of the New ORM on Your Modules
Impact of the New ORM on Your Modules
 
Odoo Performance Limits
Odoo Performance LimitsOdoo Performance Limits
Odoo Performance Limits
 
Developing New Widgets for your Views in Owl
Developing New Widgets for your Views in OwlDeveloping New Widgets for your Views in Owl
Developing New Widgets for your Views in Owl
 
Best Practices in Handling Performance Issues
Best Practices in Handling Performance IssuesBest Practices in Handling Performance Issues
Best Practices in Handling Performance Issues
 
How to Develop your own in App-Purchase Service in Odoo
How to Develop your own in App-Purchase Service in OdooHow to Develop your own in App-Purchase Service in Odoo
How to Develop your own in App-Purchase Service in Odoo
 
Odoo - Backend modules in v8
Odoo - Backend modules in v8Odoo - Backend modules in v8
Odoo - Backend modules in v8
 
Tips on how to improve the performance of your custom modules for high volume...
Tips on how to improve the performance of your custom modules for high volume...Tips on how to improve the performance of your custom modules for high volume...
Tips on how to improve the performance of your custom modules for high volume...
 
Introduction to django
Introduction to djangoIntroduction to django
Introduction to django
 
Odoo ORM Methods | Object Relational Mapping in Odoo15
Odoo ORM Methods | Object Relational Mapping in Odoo15 Odoo ORM Methods | Object Relational Mapping in Odoo15
Odoo ORM Methods | Object Relational Mapping in Odoo15
 
Deploying Moodle With High Availability and auto-scale on Microsoft Azure pla...
Deploying Moodle With High Availability and auto-scale on Microsoft Azure pla...Deploying Moodle With High Availability and auto-scale on Microsoft Azure pla...
Deploying Moodle With High Availability and auto-scale on Microsoft Azure pla...
 

Similar to Odoo Experience 2018 - Inherit from These 10 Mixins to Empower Your App

Odoo Experience 2018 - From a Web Controller to a Full CMS
Odoo Experience 2018 - From a Web Controller to a Full CMSOdoo Experience 2018 - From a Web Controller to a Full CMS
Odoo Experience 2018 - From a Web Controller to a Full CMS
ElínAnna Jónasdóttir
 
Dexterity in the Wild
Dexterity in the WildDexterity in the Wild
Dexterity in the Wild
David Glick
 
Nicolas Embleton, Advanced Angular JS
Nicolas Embleton, Advanced Angular JSNicolas Embleton, Advanced Angular JS
Nicolas Embleton, Advanced Angular JS
JavaScript Meetup HCMC
 
Dynamic Business Processes using Automated Actions
Dynamic Business Processes using Automated ActionsDynamic Business Processes using Automated Actions
Dynamic Business Processes using Automated Actions
Daniel Reis
 
Vedika C project.docx
Vedika C project.docxVedika C project.docx
Vedika C project.docx
HarshKewat1
 
Customizing the Django Admin
Customizing the Django AdminCustomizing the Django Admin
Customizing the Django AdminLincoln Loop
 
Tango with django
Tango with djangoTango with django
Tango with django
Rajan Kumar Upadhyay
 
Customise Odoo addons modules
Customise Odoo addons modulesCustomise Odoo addons modules
Customise Odoo addons modules
GLC Networks
 
Java on Google App engine
Java on Google App engineJava on Google App engine
Java on Google App engine
Michael Parker
 
How to Mess Up Your Angular UI Components
How to Mess Up Your Angular UI ComponentsHow to Mess Up Your Angular UI Components
How to Mess Up Your Angular UI Components
cagataycivici
 
Software Quality - A perspective
Software Quality - A perspectiveSoftware Quality - A perspective
Software Quality - A perspective
Thomas P Thomas
 
Iterative Methodology for Personalization Models Optimization
 Iterative Methodology for Personalization Models Optimization Iterative Methodology for Personalization Models Optimization
Iterative Methodology for Personalization Models Optimization
Sonya Liberman
 
Developing new feature in Joomla - Joomladay UK 2016
Developing new feature in Joomla - Joomladay UK 2016Developing new feature in Joomla - Joomladay UK 2016
Developing new feature in Joomla - Joomladay UK 2016
Peter Martin
 
Develop an App with the Odoo Framework
Develop an App with the Odoo FrameworkDevelop an App with the Odoo Framework
Develop an App with the Odoo Framework
Odoo
 
Zotonic tutorial EUC 2013
Zotonic tutorial EUC 2013Zotonic tutorial EUC 2013
Zotonic tutorial EUC 2013
Arjan
 
Survey Management System
Survey Management SystemSurvey Management System
Survey Management System
Laurian Staicu
 
GDayX - Advanced Angular.JS
GDayX - Advanced Angular.JSGDayX - Advanced Angular.JS
GDayX - Advanced Angular.JS
Nicolas Embleton
 
oopusingc.pptx
oopusingc.pptxoopusingc.pptx
oopusingc.pptx
MohammedAlobaidy16
 

Similar to Odoo Experience 2018 - Inherit from These 10 Mixins to Empower Your App (20)

Odoo Experience 2018 - From a Web Controller to a Full CMS
Odoo Experience 2018 - From a Web Controller to a Full CMSOdoo Experience 2018 - From a Web Controller to a Full CMS
Odoo Experience 2018 - From a Web Controller to a Full CMS
 
Dexterity in the Wild
Dexterity in the WildDexterity in the Wild
Dexterity in the Wild
 
Nicolas Embleton, Advanced Angular JS
Nicolas Embleton, Advanced Angular JSNicolas Embleton, Advanced Angular JS
Nicolas Embleton, Advanced Angular JS
 
Dynamic Business Processes using Automated Actions
Dynamic Business Processes using Automated ActionsDynamic Business Processes using Automated Actions
Dynamic Business Processes using Automated Actions
 
Vedika C project.docx
Vedika C project.docxVedika C project.docx
Vedika C project.docx
 
Customizing the Django Admin
Customizing the Django AdminCustomizing the Django Admin
Customizing the Django Admin
 
Tango with django
Tango with djangoTango with django
Tango with django
 
Customise Odoo addons modules
Customise Odoo addons modulesCustomise Odoo addons modules
Customise Odoo addons modules
 
Java on Google App engine
Java on Google App engineJava on Google App engine
Java on Google App engine
 
How to Mess Up Your Angular UI Components
How to Mess Up Your Angular UI ComponentsHow to Mess Up Your Angular UI Components
How to Mess Up Your Angular UI Components
 
Software Quality - A perspective
Software Quality - A perspectiveSoftware Quality - A perspective
Software Quality - A perspective
 
Iterative Methodology for Personalization Models Optimization
 Iterative Methodology for Personalization Models Optimization Iterative Methodology for Personalization Models Optimization
Iterative Methodology for Personalization Models Optimization
 
Developing new feature in Joomla - Joomladay UK 2016
Developing new feature in Joomla - Joomladay UK 2016Developing new feature in Joomla - Joomladay UK 2016
Developing new feature in Joomla - Joomladay UK 2016
 
Introduction to Django
Introduction to DjangoIntroduction to Django
Introduction to Django
 
Develop an App with the Odoo Framework
Develop an App with the Odoo FrameworkDevelop an App with the Odoo Framework
Develop an App with the Odoo Framework
 
Zotonic tutorial EUC 2013
Zotonic tutorial EUC 2013Zotonic tutorial EUC 2013
Zotonic tutorial EUC 2013
 
Survey Management System
Survey Management SystemSurvey Management System
Survey Management System
 
GDayX - Advanced Angular.JS
GDayX - Advanced Angular.JSGDayX - Advanced Angular.JS
GDayX - Advanced Angular.JS
 
oopusingc.pptx
oopusingc.pptxoopusingc.pptx
oopusingc.pptx
 
Django
DjangoDjango
Django
 

More from ElínAnna Jónasdóttir

Odoo Experience 2018 - Connect Your PoS to Hardware
Odoo Experience 2018 - Connect Your PoS to HardwareOdoo Experience 2018 - Connect Your PoS to Hardware
Odoo Experience 2018 - Connect Your PoS to Hardware
ElínAnna Jónasdóttir
 
Odoo Experience 2018 - Odoo Studio as a Prototyping Tool
Odoo Experience 2018 - Odoo Studio as a Prototyping ToolOdoo Experience 2018 - Odoo Studio as a Prototyping Tool
Odoo Experience 2018 - Odoo Studio as a Prototyping Tool
ElínAnna Jónasdóttir
 
Odoo Experience 2018 - Odoo Studio: A Functional Approach
Odoo Experience 2018 - Odoo Studio: A Functional ApproachOdoo Experience 2018 - Odoo Studio: A Functional Approach
Odoo Experience 2018 - Odoo Studio: A Functional Approach
ElínAnna Jónasdóttir
 
Odoo Experience 2018 - GDPR: How Odoo Can Help You with Complieance
Odoo Experience 2018 - GDPR: How Odoo Can Help You with ComplieanceOdoo Experience 2018 - GDPR: How Odoo Can Help You with Complieance
Odoo Experience 2018 - GDPR: How Odoo Can Help You with Complieance
ElínAnna Jónasdóttir
 
Odoo Experience 2018 - How to Break Odoo Security (or how to prevent it)
Odoo Experience 2018 - How to Break Odoo Security (or how to prevent it)Odoo Experience 2018 - How to Break Odoo Security (or how to prevent it)
Odoo Experience 2018 - How to Break Odoo Security (or how to prevent it)
ElínAnna Jónasdóttir
 
Odoo Experience 2018 - Multi-Channel Sales: The Future of Retail
Odoo Experience 2018 - Multi-Channel Sales: The Future of RetailOdoo Experience 2018 - Multi-Channel Sales: The Future of Retail
Odoo Experience 2018 - Multi-Channel Sales: The Future of Retail
ElínAnna Jónasdóttir
 
Odoo Experience 2018 - Speed Up Credit Collection with Automated Follow-Ups
Odoo Experience 2018 - Speed Up Credit Collection with Automated Follow-UpsOdoo Experience 2018 - Speed Up Credit Collection with Automated Follow-Ups
Odoo Experience 2018 - Speed Up Credit Collection with Automated Follow-Ups
ElínAnna Jónasdóttir
 
Odoo Experience 2018 - Improve Your Visibility and Prospect Better with Odoo
Odoo Experience 2018 - Improve Your Visibility and Prospect Better with OdooOdoo Experience 2018 - Improve Your Visibility and Prospect Better with Odoo
Odoo Experience 2018 - Improve Your Visibility and Prospect Better with Odoo
ElínAnna Jónasdóttir
 
Odoo Experience 2018 - Organize Your Operations in a Startup Environment
Odoo Experience 2018 - Organize Your Operations in a Startup EnvironmentOdoo Experience 2018 - Organize Your Operations in a Startup Environment
Odoo Experience 2018 - Organize Your Operations in a Startup Environment
ElínAnna Jónasdóttir
 
Odoo Experience 2018 - Best Practices to Close Deals
Odoo Experience 2018 - Best Practices to Close DealsOdoo Experience 2018 - Best Practices to Close Deals
Odoo Experience 2018 - Best Practices to Close Deals
ElínAnna Jónasdóttir
 
Odoo Experience 2018 - Customer Success Team: How Do We Work?
Odoo Experience 2018 - Customer Success Team: How Do We Work?Odoo Experience 2018 - Customer Success Team: How Do We Work?
Odoo Experience 2018 - Customer Success Team: How Do We Work?
ElínAnna Jónasdóttir
 
Odoo Experience 2018 - Customer Success Team: Meet our Experts
Odoo Experience 2018 - Customer Success Team: Meet our ExpertsOdoo Experience 2018 - Customer Success Team: Meet our Experts
Odoo Experience 2018 - Customer Success Team: Meet our Experts
ElínAnna Jónasdóttir
 
Odoo Experience 2018 - How a Feedback Loop Helps to Fine-Tune Your Manufactu...
Odoo Experience 2018 -  How a Feedback Loop Helps to Fine-Tune Your Manufactu...Odoo Experience 2018 -  How a Feedback Loop Helps to Fine-Tune Your Manufactu...
Odoo Experience 2018 - How a Feedback Loop Helps to Fine-Tune Your Manufactu...
ElínAnna Jónasdóttir
 
Odoo Experience 2018 - Successful Import of Big Data with an Efficient Tool
Odoo Experience 2018 - Successful Import of Big Data with an Efficient ToolOdoo Experience 2018 - Successful Import of Big Data with an Efficient Tool
Odoo Experience 2018 - Successful Import of Big Data with an Efficient Tool
ElínAnna Jónasdóttir
 
Odoo Experience 2018 - Inventory: Advanced Flow with the New Barcode
Odoo Experience 2018 - Inventory: Advanced Flow with the New BarcodeOdoo Experience 2018 - Inventory: Advanced Flow with the New Barcode
Odoo Experience 2018 - Inventory: Advanced Flow with the New Barcode
ElínAnna Jónasdóttir
 
Odoo Experience 2018 - Easypost: New Shipping Connector
Odoo Experience 2018 - Easypost: New Shipping Connector Odoo Experience 2018 - Easypost: New Shipping Connector
Odoo Experience 2018 - Easypost: New Shipping Connector
ElínAnna Jónasdóttir
 
Odoo Experience 2018 - Project Methodology: The Editor Stance
Odoo Experience 2018 - Project Methodology: The Editor StanceOdoo Experience 2018 - Project Methodology: The Editor Stance
Odoo Experience 2018 - Project Methodology: The Editor Stance
ElínAnna Jónasdóttir
 
Odoo Experience 2018 - Grow Your Business with In-App Purchases
Odoo Experience 2018 -  Grow Your Business with In-App PurchasesOdoo Experience 2018 -  Grow Your Business with In-App Purchases
Odoo Experience 2018 - Grow Your Business with In-App Purchases
ElínAnna Jónasdóttir
 
Odoo Experience 2018 - All You Need to Know About Odoo's Partnership
Odoo Experience 2018 - All You Need to Know About Odoo's PartnershipOdoo Experience 2018 - All You Need to Know About Odoo's Partnership
Odoo Experience 2018 - All You Need to Know About Odoo's Partnership
ElínAnna Jónasdóttir
 
Odoo Experience 2018 - How to Manage Accounting Firms with Odoo?
Odoo Experience 2018 - How to Manage Accounting Firms with Odoo?Odoo Experience 2018 - How to Manage Accounting Firms with Odoo?
Odoo Experience 2018 - How to Manage Accounting Firms with Odoo?
ElínAnna Jónasdóttir
 

More from ElínAnna Jónasdóttir (20)

Odoo Experience 2018 - Connect Your PoS to Hardware
Odoo Experience 2018 - Connect Your PoS to HardwareOdoo Experience 2018 - Connect Your PoS to Hardware
Odoo Experience 2018 - Connect Your PoS to Hardware
 
Odoo Experience 2018 - Odoo Studio as a Prototyping Tool
Odoo Experience 2018 - Odoo Studio as a Prototyping ToolOdoo Experience 2018 - Odoo Studio as a Prototyping Tool
Odoo Experience 2018 - Odoo Studio as a Prototyping Tool
 
Odoo Experience 2018 - Odoo Studio: A Functional Approach
Odoo Experience 2018 - Odoo Studio: A Functional ApproachOdoo Experience 2018 - Odoo Studio: A Functional Approach
Odoo Experience 2018 - Odoo Studio: A Functional Approach
 
Odoo Experience 2018 - GDPR: How Odoo Can Help You with Complieance
Odoo Experience 2018 - GDPR: How Odoo Can Help You with ComplieanceOdoo Experience 2018 - GDPR: How Odoo Can Help You with Complieance
Odoo Experience 2018 - GDPR: How Odoo Can Help You with Complieance
 
Odoo Experience 2018 - How to Break Odoo Security (or how to prevent it)
Odoo Experience 2018 - How to Break Odoo Security (or how to prevent it)Odoo Experience 2018 - How to Break Odoo Security (or how to prevent it)
Odoo Experience 2018 - How to Break Odoo Security (or how to prevent it)
 
Odoo Experience 2018 - Multi-Channel Sales: The Future of Retail
Odoo Experience 2018 - Multi-Channel Sales: The Future of RetailOdoo Experience 2018 - Multi-Channel Sales: The Future of Retail
Odoo Experience 2018 - Multi-Channel Sales: The Future of Retail
 
Odoo Experience 2018 - Speed Up Credit Collection with Automated Follow-Ups
Odoo Experience 2018 - Speed Up Credit Collection with Automated Follow-UpsOdoo Experience 2018 - Speed Up Credit Collection with Automated Follow-Ups
Odoo Experience 2018 - Speed Up Credit Collection with Automated Follow-Ups
 
Odoo Experience 2018 - Improve Your Visibility and Prospect Better with Odoo
Odoo Experience 2018 - Improve Your Visibility and Prospect Better with OdooOdoo Experience 2018 - Improve Your Visibility and Prospect Better with Odoo
Odoo Experience 2018 - Improve Your Visibility and Prospect Better with Odoo
 
Odoo Experience 2018 - Organize Your Operations in a Startup Environment
Odoo Experience 2018 - Organize Your Operations in a Startup EnvironmentOdoo Experience 2018 - Organize Your Operations in a Startup Environment
Odoo Experience 2018 - Organize Your Operations in a Startup Environment
 
Odoo Experience 2018 - Best Practices to Close Deals
Odoo Experience 2018 - Best Practices to Close DealsOdoo Experience 2018 - Best Practices to Close Deals
Odoo Experience 2018 - Best Practices to Close Deals
 
Odoo Experience 2018 - Customer Success Team: How Do We Work?
Odoo Experience 2018 - Customer Success Team: How Do We Work?Odoo Experience 2018 - Customer Success Team: How Do We Work?
Odoo Experience 2018 - Customer Success Team: How Do We Work?
 
Odoo Experience 2018 - Customer Success Team: Meet our Experts
Odoo Experience 2018 - Customer Success Team: Meet our ExpertsOdoo Experience 2018 - Customer Success Team: Meet our Experts
Odoo Experience 2018 - Customer Success Team: Meet our Experts
 
Odoo Experience 2018 - How a Feedback Loop Helps to Fine-Tune Your Manufactu...
Odoo Experience 2018 -  How a Feedback Loop Helps to Fine-Tune Your Manufactu...Odoo Experience 2018 -  How a Feedback Loop Helps to Fine-Tune Your Manufactu...
Odoo Experience 2018 - How a Feedback Loop Helps to Fine-Tune Your Manufactu...
 
Odoo Experience 2018 - Successful Import of Big Data with an Efficient Tool
Odoo Experience 2018 - Successful Import of Big Data with an Efficient ToolOdoo Experience 2018 - Successful Import of Big Data with an Efficient Tool
Odoo Experience 2018 - Successful Import of Big Data with an Efficient Tool
 
Odoo Experience 2018 - Inventory: Advanced Flow with the New Barcode
Odoo Experience 2018 - Inventory: Advanced Flow with the New BarcodeOdoo Experience 2018 - Inventory: Advanced Flow with the New Barcode
Odoo Experience 2018 - Inventory: Advanced Flow with the New Barcode
 
Odoo Experience 2018 - Easypost: New Shipping Connector
Odoo Experience 2018 - Easypost: New Shipping Connector Odoo Experience 2018 - Easypost: New Shipping Connector
Odoo Experience 2018 - Easypost: New Shipping Connector
 
Odoo Experience 2018 - Project Methodology: The Editor Stance
Odoo Experience 2018 - Project Methodology: The Editor StanceOdoo Experience 2018 - Project Methodology: The Editor Stance
Odoo Experience 2018 - Project Methodology: The Editor Stance
 
Odoo Experience 2018 - Grow Your Business with In-App Purchases
Odoo Experience 2018 -  Grow Your Business with In-App PurchasesOdoo Experience 2018 -  Grow Your Business with In-App Purchases
Odoo Experience 2018 - Grow Your Business with In-App Purchases
 
Odoo Experience 2018 - All You Need to Know About Odoo's Partnership
Odoo Experience 2018 - All You Need to Know About Odoo's PartnershipOdoo Experience 2018 - All You Need to Know About Odoo's Partnership
Odoo Experience 2018 - All You Need to Know About Odoo's Partnership
 
Odoo Experience 2018 - How to Manage Accounting Firms with Odoo?
Odoo Experience 2018 - How to Manage Accounting Firms with Odoo?Odoo Experience 2018 - How to Manage Accounting Firms with Odoo?
Odoo Experience 2018 - How to Manage Accounting Firms with Odoo?
 

Recently uploaded

Media as a Mind Controlling Strategy In Old and Modern Era
Media as a Mind Controlling Strategy In Old and Modern EraMedia as a Mind Controlling Strategy In Old and Modern Era
Media as a Mind Controlling Strategy In Old and Modern Era
faizulhassanfaiz1670
 
Presentatie 8. Joost van der Linde & Daniel Anderton - Eliq 28 mei 2024
Presentatie 8. Joost van der Linde & Daniel Anderton - Eliq 28 mei 2024Presentatie 8. Joost van der Linde & Daniel Anderton - Eliq 28 mei 2024
Presentatie 8. Joost van der Linde & Daniel Anderton - Eliq 28 mei 2024
Dutch Power
 
Mastering the Concepts Tested in the Databricks Certified Data Engineer Assoc...
Mastering the Concepts Tested in the Databricks Certified Data Engineer Assoc...Mastering the Concepts Tested in the Databricks Certified Data Engineer Assoc...
Mastering the Concepts Tested in the Databricks Certified Data Engineer Assoc...
SkillCertProExams
 
Presentatie 4. Jochen Cremer - TU Delft 28 mei 2024
Presentatie 4. Jochen Cremer - TU Delft 28 mei 2024Presentatie 4. Jochen Cremer - TU Delft 28 mei 2024
Presentatie 4. Jochen Cremer - TU Delft 28 mei 2024
Dutch Power
 
somanykidsbutsofewfathers-140705000023-phpapp02.pptx
somanykidsbutsofewfathers-140705000023-phpapp02.pptxsomanykidsbutsofewfathers-140705000023-phpapp02.pptx
somanykidsbutsofewfathers-140705000023-phpapp02.pptx
Howard Spence
 
Doctoral Symposium at the 17th IEEE International Conference on Software Test...
Doctoral Symposium at the 17th IEEE International Conference on Software Test...Doctoral Symposium at the 17th IEEE International Conference on Software Test...
Doctoral Symposium at the 17th IEEE International Conference on Software Test...
Sebastiano Panichella
 
International Workshop on Artificial Intelligence in Software Testing
International Workshop on Artificial Intelligence in Software TestingInternational Workshop on Artificial Intelligence in Software Testing
International Workshop on Artificial Intelligence in Software Testing
Sebastiano Panichella
 
Collapsing Narratives: Exploring Non-Linearity • a micro report by Rosie Wells
Collapsing Narratives: Exploring Non-Linearity • a micro report by Rosie WellsCollapsing Narratives: Exploring Non-Linearity • a micro report by Rosie Wells
Collapsing Narratives: Exploring Non-Linearity • a micro report by Rosie Wells
Rosie Wells
 
Burning Issue Presentation By Kenmaryon.pdf
Burning Issue Presentation By Kenmaryon.pdfBurning Issue Presentation By Kenmaryon.pdf
Burning Issue Presentation By Kenmaryon.pdf
kkirkland2
 
2024-05-30_meetup_devops_aix-marseille.pdf
2024-05-30_meetup_devops_aix-marseille.pdf2024-05-30_meetup_devops_aix-marseille.pdf
2024-05-30_meetup_devops_aix-marseille.pdf
Frederic Leger
 
Announcement of 18th IEEE International Conference on Software Testing, Verif...
Announcement of 18th IEEE International Conference on Software Testing, Verif...Announcement of 18th IEEE International Conference on Software Testing, Verif...
Announcement of 18th IEEE International Conference on Software Testing, Verif...
Sebastiano Panichella
 
Supercharge your AI - SSP Industry Breakout Session 2024-v2_1.pdf
Supercharge your AI - SSP Industry Breakout Session 2024-v2_1.pdfSupercharge your AI - SSP Industry Breakout Session 2024-v2_1.pdf
Supercharge your AI - SSP Industry Breakout Session 2024-v2_1.pdf
Access Innovations, Inc.
 
Gregory Harris - Cycle 2 - Civics Presentation
Gregory Harris - Cycle 2 - Civics PresentationGregory Harris - Cycle 2 - Civics Presentation
Gregory Harris - Cycle 2 - Civics Presentation
gharris9
 
Bonzo subscription_hjjjjjjjj5hhhhhhh_2024.pdf
Bonzo subscription_hjjjjjjjj5hhhhhhh_2024.pdfBonzo subscription_hjjjjjjjj5hhhhhhh_2024.pdf
Bonzo subscription_hjjjjjjjj5hhhhhhh_2024.pdf
khadija278284
 
Obesity causes and management and associated medical conditions
Obesity causes and management and associated medical conditionsObesity causes and management and associated medical conditions
Obesity causes and management and associated medical conditions
Faculty of Medicine And Health Sciences
 
Gregory Harris' Civics Presentation.pptx
Gregory Harris' Civics Presentation.pptxGregory Harris' Civics Presentation.pptx
Gregory Harris' Civics Presentation.pptx
gharris9
 
Tom tresser burning issue.pptx My Burning issue
Tom tresser burning issue.pptx My Burning issueTom tresser burning issue.pptx My Burning issue
Tom tresser burning issue.pptx My Burning issue
amekonnen
 
María Carolina Martínez - eCommerce Day Colombia 2024
María Carolina Martínez - eCommerce Day Colombia 2024María Carolina Martínez - eCommerce Day Colombia 2024
María Carolina Martínez - eCommerce Day Colombia 2024
eCommerce Institute
 
AWANG ANIQKMALBIN AWANG TAJUDIN B22080004 ASSIGNMENT 2 MPU3193 PHILOSOPHY AND...
AWANG ANIQKMALBIN AWANG TAJUDIN B22080004 ASSIGNMENT 2 MPU3193 PHILOSOPHY AND...AWANG ANIQKMALBIN AWANG TAJUDIN B22080004 ASSIGNMENT 2 MPU3193 PHILOSOPHY AND...
AWANG ANIQKMALBIN AWANG TAJUDIN B22080004 ASSIGNMENT 2 MPU3193 PHILOSOPHY AND...
AwangAniqkmals
 

Recently uploaded (19)

Media as a Mind Controlling Strategy In Old and Modern Era
Media as a Mind Controlling Strategy In Old and Modern EraMedia as a Mind Controlling Strategy In Old and Modern Era
Media as a Mind Controlling Strategy In Old and Modern Era
 
Presentatie 8. Joost van der Linde & Daniel Anderton - Eliq 28 mei 2024
Presentatie 8. Joost van der Linde & Daniel Anderton - Eliq 28 mei 2024Presentatie 8. Joost van der Linde & Daniel Anderton - Eliq 28 mei 2024
Presentatie 8. Joost van der Linde & Daniel Anderton - Eliq 28 mei 2024
 
Mastering the Concepts Tested in the Databricks Certified Data Engineer Assoc...
Mastering the Concepts Tested in the Databricks Certified Data Engineer Assoc...Mastering the Concepts Tested in the Databricks Certified Data Engineer Assoc...
Mastering the Concepts Tested in the Databricks Certified Data Engineer Assoc...
 
Presentatie 4. Jochen Cremer - TU Delft 28 mei 2024
Presentatie 4. Jochen Cremer - TU Delft 28 mei 2024Presentatie 4. Jochen Cremer - TU Delft 28 mei 2024
Presentatie 4. Jochen Cremer - TU Delft 28 mei 2024
 
somanykidsbutsofewfathers-140705000023-phpapp02.pptx
somanykidsbutsofewfathers-140705000023-phpapp02.pptxsomanykidsbutsofewfathers-140705000023-phpapp02.pptx
somanykidsbutsofewfathers-140705000023-phpapp02.pptx
 
Doctoral Symposium at the 17th IEEE International Conference on Software Test...
Doctoral Symposium at the 17th IEEE International Conference on Software Test...Doctoral Symposium at the 17th IEEE International Conference on Software Test...
Doctoral Symposium at the 17th IEEE International Conference on Software Test...
 
International Workshop on Artificial Intelligence in Software Testing
International Workshop on Artificial Intelligence in Software TestingInternational Workshop on Artificial Intelligence in Software Testing
International Workshop on Artificial Intelligence in Software Testing
 
Collapsing Narratives: Exploring Non-Linearity • a micro report by Rosie Wells
Collapsing Narratives: Exploring Non-Linearity • a micro report by Rosie WellsCollapsing Narratives: Exploring Non-Linearity • a micro report by Rosie Wells
Collapsing Narratives: Exploring Non-Linearity • a micro report by Rosie Wells
 
Burning Issue Presentation By Kenmaryon.pdf
Burning Issue Presentation By Kenmaryon.pdfBurning Issue Presentation By Kenmaryon.pdf
Burning Issue Presentation By Kenmaryon.pdf
 
2024-05-30_meetup_devops_aix-marseille.pdf
2024-05-30_meetup_devops_aix-marseille.pdf2024-05-30_meetup_devops_aix-marseille.pdf
2024-05-30_meetup_devops_aix-marseille.pdf
 
Announcement of 18th IEEE International Conference on Software Testing, Verif...
Announcement of 18th IEEE International Conference on Software Testing, Verif...Announcement of 18th IEEE International Conference on Software Testing, Verif...
Announcement of 18th IEEE International Conference on Software Testing, Verif...
 
Supercharge your AI - SSP Industry Breakout Session 2024-v2_1.pdf
Supercharge your AI - SSP Industry Breakout Session 2024-v2_1.pdfSupercharge your AI - SSP Industry Breakout Session 2024-v2_1.pdf
Supercharge your AI - SSP Industry Breakout Session 2024-v2_1.pdf
 
Gregory Harris - Cycle 2 - Civics Presentation
Gregory Harris - Cycle 2 - Civics PresentationGregory Harris - Cycle 2 - Civics Presentation
Gregory Harris - Cycle 2 - Civics Presentation
 
Bonzo subscription_hjjjjjjjj5hhhhhhh_2024.pdf
Bonzo subscription_hjjjjjjjj5hhhhhhh_2024.pdfBonzo subscription_hjjjjjjjj5hhhhhhh_2024.pdf
Bonzo subscription_hjjjjjjjj5hhhhhhh_2024.pdf
 
Obesity causes and management and associated medical conditions
Obesity causes and management and associated medical conditionsObesity causes and management and associated medical conditions
Obesity causes and management and associated medical conditions
 
Gregory Harris' Civics Presentation.pptx
Gregory Harris' Civics Presentation.pptxGregory Harris' Civics Presentation.pptx
Gregory Harris' Civics Presentation.pptx
 
Tom tresser burning issue.pptx My Burning issue
Tom tresser burning issue.pptx My Burning issueTom tresser burning issue.pptx My Burning issue
Tom tresser burning issue.pptx My Burning issue
 
María Carolina Martínez - eCommerce Day Colombia 2024
María Carolina Martínez - eCommerce Day Colombia 2024María Carolina Martínez - eCommerce Day Colombia 2024
María Carolina Martínez - eCommerce Day Colombia 2024
 
AWANG ANIQKMALBIN AWANG TAJUDIN B22080004 ASSIGNMENT 2 MPU3193 PHILOSOPHY AND...
AWANG ANIQKMALBIN AWANG TAJUDIN B22080004 ASSIGNMENT 2 MPU3193 PHILOSOPHY AND...AWANG ANIQKMALBIN AWANG TAJUDIN B22080004 ASSIGNMENT 2 MPU3193 PHILOSOPHY AND...
AWANG ANIQKMALBIN AWANG TAJUDIN B22080004 ASSIGNMENT 2 MPU3193 PHILOSOPHY AND...
 

Odoo Experience 2018 - Inherit from These 10 Mixins to Empower Your App

  • 1. Let us recode everything from scratch. Or not. EXPERIENCE 2018 • Software Engineer, RD Dummies Team Leader
  • 2.
  • 6. ● Mixin class: extracts transversal features ● AbstractModel: no table, only for definition ● offer features through inheritance ● e.g. messaging mechanism, customer satisfaction request, ...
  • 7. class MailThread(models.AbstractModel): _name = 'mail.thread' _description = 'Mail Thread Mixin' message_ids = fields.One2many('mail.message', 'Messages') message_follower_ids = fields.One2many('mail.followers', 'Followers') def message_post(self, body): # do stuff def message_subscribe(self, partners): # do stuff
  • 8. ● Mixin class: extracts transversal features ● Inheritance: “copy” fields on child class MailThread(models.AbstractModel): _name = 'mail.thread' message_ids = fields.One2many(...) message_follower_ids = fields.One2many(...) class Plant(models.Model): _inherit = ['mail.thread'] name = fields.Char('Plant Name') class Order(models.Model): _inherit = ['mail.thread'] name = fields.Char('Reference')
  • 9. ● Mixin class: extracts transversal features ● Inheritance: “copy” fields on child class MailThread(models.AbstractModel): _name = 'mail.thread' message_ids = fields.One2many(...) message_follower_ids = fields.One2many(...) class Plant(models.Model): _inherit = ['mail.thread'] name = fields.Char('Plant Name') message_ids = fields.One2many(...) message_follower_ids = fields.One2many(...) class Order(models.Model): _inherit = ['mail.thread'] name = fields.Char('Reference') message_ids = fields.One2many(...) message_follower_ids = fields.One2many(...)
  • 10. ● Mixin class: extracts transversal features ● Inheritance: class inheritance: methods, super(), ... class MailThread(models.AbstractModel): _name = 'mail.thread' message_ids = fields.One2many(...) message_follower_ids = fields.One2many(...) def message_post(self, body): # do stuff return message class Plant(models.Model): _name = 'nursery.plant' _inherit = ['mail.thread'] name = fields.Char('Plant Name') price = fields.Integer('Plant Price') def say_hello(self): self.message_post('Hello') def message_post(self, body): if self.message_ids: ... self.message_follower_ids.write({}) return super()
  • 11. ● Mixin class: extracts transversal features ● Inherit abstract class itself (Since 11.0) ○ tweaking abstract through inheritance applies to all childs class MyOwnMailThread(models.AbstractModel): _name = 'mail.thread' _inherit = 'mail.thread' message_my_own = fields.Integer(...) def message_my_own_stuff(self): ... return def message_post(self, body): # do more stuff self.message_my_own_stuff() return super()
  • 15. ● Communication & Organization ○ Discuss on a document, send mailings ○ Schedule activities ● Marketing ○ Get customer satisfaction insights ○ Track campaigns and mediums ● Website ○ Manage document publication ○ Promote pages
  • 16. ● Communication & Organization ○ Discuss on a document, send mailings ○ Schedule activities ● Marketing ○ Get customer satisfaction insights ○ Track campaigns and mediums ● Website ○ Manage document publication ○ Promote pages ● mail.thread ● mail.activity.mixin ● rating.mixin ● utm.mixin ● portal, website.published ● website.seo.metadata
  • 17. ● Features of mixins ● How to implement them ● Code bits ● Live result ● Documentation ? ○ Odoo code ○ Documentation ○ https://github.com/tivisse/odoodays-2018
  • 18.
  • 19. ● Add messaging to any class ● Auto-interfacing with e-mail ● How to use: ○ inherit mail.thread ○ add widgets ○ have fun !
  • 20. ● Add messaging to any class ● Auto-interfacing with e-mail ● How to use: ○ Inherit mail.thread ○ Add widgets ○ Have fun ! class Plant(models.Model): _name = 'nursery.plant' _description = 'Plant' _inherit = ['mail.thread'] <div class="oe_chatter"> <field name="message_follower_ids" widget="mail_followers"/> <field name="message_ids" widget="mail_thread"/> </div> { 'name': Plant Nursery, 'depends': ['mail'], }
  • 21. ● Messages linked to a document class Message(models.Model): _name = 'mail.message' _description = 'Message' model = fields.Char(...) res_id = fields.Integer(...) notified_partner_ids = fields.Many2Many(...) def create(self, values): msg = super() msg._notify() return msg def _notify(self): followers = self.get_followers() followers.notify() followers.send_mail() class Plant(models.Model): _inherit = ['mail.thread'] # coming from mail.thread inheritance message_ids = fields.One2many(...)
  • 22. ● Messages linked to a document ● Communication through Chatter class MailThread(models.AbstractModel): _name = 'mail.thread' message_ids = fields.One2many(...) def message_post(self, subject, body, **kw): self.env['mail.message'].create({ 'model': self.model, 'res_id': self.res_id}) class Plant(models.Model): _name = 'nursery.plant' _inherit = ['mail.thread'] def message_post(self, subject, body, **kw): super()
  • 23. ● Messages linked to a document ● Communication through Chatter ● Followers management class MailThread(models.AbstractModel): _name = 'mail.thread' message_follower_ids = fields.One2many(...) def message_subscribe(self, partners, channels): # add followers and listeners Follower.create(partners) class Plant(models.Model): _name = 'nursery.plant' _inherit = ['mail.thread'] def message_subscribe(self, partners, channels): super()
  • 24. ● Process and route incoming emails ● Ensure thread detection ● App-specific behavior on new thread or on update class MailThread(models.AbstractModel): _name = 'mail.thread' def message_process(self, email): # process email values def message_route(self, message): # heuristics when incoming email detected class Plant(models.Model): _name = 'nursery.plant' _inherit = ['mail.thread'] def message_new(self, message): # do sthg when creating from email super() def message_update(self, message): # do sthg when incoming email super()
  • 25. ● Activities management on document ● Interfacing with Chatter ● How to use: ○ inherit mail.activity.mixin ○ add widgets ○ have much fun ! class Plant(models.Model): _name = 'nursery.plant' _description = 'Plant' _inherit = ['mail.thread', 'mail.activity.mixin'] <div class="oe_chatter"> <field name="message_ids" widget="mail_thread"/> <field name="activity_ids" widget="mail_activity"/> </div> { 'name': Plant Nursery, 'depends': ['mail'], }
  • 26. ● Activities management on document ● Activity-based state ● Filters class Plant(models.Model): _name = 'nursery.plant' _description = 'Plant' _inherit = ['mail.thread', 'mail.activity.mixin'] # coming from mail.activity inheritance activity_ids = fields.One2many('mail.activity') activity_state = fields.Selection([ ('overdue', 'Overdue'), ('today', 'Today'), ('planned', 'Planned')])
  • 27. ● Automatic activity (re)scheduling or closing ● Specify a responsible on a given business flow class MailActivityMixin(models.AbstractModel): _name = 'mail.activity.mixin' def activity_schedule(self, type, date): # Schedule an activity def activity_feedback(self, feedback): # Set activities as done def activity_unlink(self): # Delete activities class Order(models.Model): _name = 'nursery.order' _inherit = ['mail.thread', 'mail.activity.mixin'] def create(self, vals): res = super() res.activity_schedule()
  • 28. ● Automatic activity (re)scheduling or closing ● Specify a responsible on a given business flow class Order(models.Model): _name = 'nursery.order' _inherit = ['mail.thread', 'mail.activity.mixin'] @api.model def create(self, vals): res = super(Order, self).create(vals) res.activity_schedule( 'mail.mail_activity_data_todo', user_id=self.env.ref('base.user_demo').id, date_deadline=fields.Date.today() + relativedelta(days=1), summary=_('Pack the order')) return res def action_confirm(self): if self.state != 'draft': return self.activity_feedback(['mail.mail_activity_data_todo']) return self.write({ 'state': 'open', 'date_open': fields.Datetime.now(), })
  • 30.
  • 31. ● Add rating on any class ● Request rating via email/route ● Analyse your ratings ● How to use: ○ It’s a bit of work class Plant(models.Model): _name = 'nursery.plant' _description = 'Plant' _inherit = ['mail.thread', 'rating.mixin'] { 'name': Plant Nursery, 'depends': ['rating'] } class RatingMixin(models.AbstractModel): _name = 'rating.mixin' rating_ids = fields.One2many('rating.rating', ...) rating_last_value = fields.Float(...) rating_last_feedback = fields.Text(...) rating_count = fields.Integer(...)
  • 32. ● Rated partner (user_id.partner_id field) ○ rating_get_rated_partner_id ○ In our case, nothing to do class RatingMixin(models.AbstractModel): _name = 'rating.mixin' def rating_get_rated_partner_id(self): if hasattr(self, 'user_id') and self.user_id.partner_id: return self.user_id.partner_id return self.env['res.partner']
  • 33. ● Rated partner (user_id.partner_id field) ○ rating_get_rated_partner_id ● Customer (partner_id field) ○ rating_get_partner_id ○ Need to override class RatingMixin(models.AbstractModel): _name = 'rating.mixin' def rating_get_partner_id(self): if self.customer_id.partner_id: return self.customer_id.partner_id return self.env['res.partner'] class Customer(models.Model): _name = 'nursery.customer' partner_id = fields.Many2one('res.partner') class Order(models.Model): _name = 'nursery.order' def rating_get_partner_id(self): if self.customer_id.partner_id: return self.customer_id.partner_id return self.env['res.partner']
  • 34. ● Rated partner (user_id.partner_id field) ○ rating_get_rated_partner_id ● Customer (partner_id field) ○ rating_get_partner_id ● Access token ○ rating_get_access_token
  • 35. ● Rated partner (user_id.partner_id field) ○ rating_get_rated_partner_id ● Customer (partner_id field) ○ rating_get_partner_id ● Access token ○ rating_get_access_token ● Routes (/rating/<token>/<score>)
  • 36. ● Rated partner (user_id.partner_id field) ○ rating_get_rated_partner_id ● Customer (partner_id field) ○ rating_get_partner_id ● Access token ○ rating_get_access_token ● Routes (/rating/<token>/<score>) ● Email Template using this data
  • 37. ● Email Template using this data <record id="mail_template_plant_order_rating" model="mail.template"> <field name="name">Plant: Rating Request</field> <field name="email_from">${(object.rating_get_rated_partner_id().email or '') | safe}</field> <field name="subject">${object.name}: Service Rating Request</field> <field name="model_id" ref="plant_nursery.model_nursery_order"/> <field name="partner_to" >${object.rating_get_partner_id().id}</field> <field name="auto_delete" eval="True"/> <field name="body_html" type="html"> <div> % set access_token = object.rating_get_access_token() <!-- Insert Beautiful Email Stuff --> <table> <tr> <td><a href="/rating/${access_token}/10"><img src="satisfied.png"/></a></td> <td><a href="/rating/${access_token}/5"><img src="not_satisfied.png"/></a></td> <td><a href="/rating/${access_token}/1"><img src="highly_not_satisfied.png"/></a></td> </tr> </table> <!-- Insert Ending Beautiful Email Stuff --> </div> </field> </record>
  • 38.
  • 39. ● Track incoming visitors ● Pre-built with three fields: campaign, source, medium ● Simple to extend class Plant(models.Model): _name = 'nursery.plant' _description = 'Plant' _inherit = ['utm.mixin'] class UtmMixin(models.AbstractModel): _name = 'utm.mixin' campaign_id = fields.Many2one('utm.campaign') source_id = fields.Many2one('utm.source') medium_id = fields.Many2one('utm.medium') { 'name': Plant Nursery, 'depends': ['utm'], }
  • 40. ● Track incoming visitors ● Pre-built with three fields: campaign, source, medium ● Simple to extend ● URL parsing class Plant(models.Model): _name = 'nursery.plant' _description = 'Plant' _inherit = ['utm.mixin'] http://127.0.0.1:8069/plants?utm_campaign=sale&utm_medium=facebook&utm_source=facebook_ad s
  • 42.
  • 43. ● ‘Optimize’ SE rankings ● Add fields ○ Page title ○ Keywords ○ Description class Plant(models.Model): _name = 'nursery.plant' _description = 'Plant' _inherit = ['website.seo.metadata'] { 'name': Plant Nursery, 'depends': ['website'], } class SeoMetadata(models.AbstractModel): _name = 'website.seo.metadata' website_meta_title = fields.Char('') website_meta_description = fields.Text('') website_meta_keywords = fields.Char('') website_meta_og_img = fields.Char('')
  • 44. ● ‘main_object’ magic in website ● Website promote button ● Set SEO metadata @route('/plant/<model("nursery.plant"):plant>/', type='http', auth='public, website=True) def plant(self, plant, **post): values = { 'main_object': plant, 'plant': plant, 'stuff': post.get('stuff', 'brol'), } return request.render("plant_page", values)
  • 45. ● ‘main_object’ magic in website ● Website promote button ● Set SEO metadata @route('/plant/<model("nursery.plant"):plant>/', type='http', auth='public, website=True) def plant(self, plant, **post): values = { 'main_object': plant, 'plant': plant, 'stuff': post.get('stuff', 'brol'), } return request.render("plant_page", values)
  • 46.
  • 47. ● Control visibility of documents ● Add fields ○ published ○ URL (slug) ● Access rights & route management still up to you ! class Plant(models.Model): _name = 'nursery.plant' _description = 'Plant' _inherit = ['website.published.mixin'] { 'name': Plant Nursery, 'depends': ['website'], } class WebsitePublishedMixin(models.AbstractModel): _name = "website.published.mixin" website_published = fields.Boolean('') website_url = fields.Char(compute='_compute_website_url') @api.multi def _compute_website_url(self): for record in self: record.website_url = '#'
  • 48. ● Control visibility of documents ● Wesite URL: computed field ○ -> slug (/plant/tree-1) ● Backend: use website_button ○ -> jump to website_url <button class="oe_stat_button" name="website_publish_button" type="object" icon="fa-globe"> <field name="website_published" widget="website_button"/> </button> from odoo.addons.http_routing.models.ir_http import slug class Plant(models.Model): _name = 'nursery.plant' _inherit = ['website.published.mixin'] def _compute_website_url(self): for plant in self: plant.website_url = '/plant/%s' % slug(plant)
  • 49. ● publish_management widget ● Link backend / frontend ○ Give action to execute <t t-call="website.publish_management"> <t t-set="object" t-value="plant"/> <t t-set="publish_edit" t-value="True"/> <t t-set="action" t-value="'plant_nursery.action_nursery_plant"/> </t>
  • 50. ● Restrict document to a specific website ● Add website_id ● Add a method to be used in routes class Plant(models.Model): _name = 'nursery.plant' _description = 'Plant' _inherit = ['website.multi.mixin'] { 'name': Plant Nursery, 'depends': ['website'], } class WebsiteMultiMixin(models.AbstractModel): _name = 'website.multi.mixin' website_id = fields.Many2one('website') @api.multi def can_access_from_current_website(self, website_id=False): # Specify if the record can be accessed on this website
  • 51. ● Publish document on a specific website ● Add website_id ● Add a method _compute_website_published class Plant(models.Model): _name = 'nursery.plant' _description = 'Plant' _inherit = ['website.published.multi.mixin'] { 'name': Plant Nursery, 'depends': ['website'], } class WebsitePublishedMultiMixin(models.AbstractModel): _name = 'website.published.multi.mixin' website_id = fields.Many2one('website') website_published = fields.Boolean(compute='_compute_website_published') def _compute_website_published(self): # Specify if the record is published on this website
  • 52. ● Document - and App- specific portal url computation class Plant(models.Model): _name = 'nursery.plant' _description = 'Plant' _inherit = ['portal.mixin'] { 'name': Plant Nursery, 'depends': ['portal'], }
  • 53. ● Document - and App- specific portal url computation ● Generic URL computation ○ /mail/view controller ○ access_token ○ partner_id ○ integration with auth_signup class PortalMixin(models.AbstractModel): _name = "portal.mixin" access_url = fields.Char(compute='_compute_access_url') access_token = fields.Char('Security Token') access_warning = fields.Text(compute="_compute_access_warning") def _compute_access_warning(self): # Set a warning text if the record can't be shared access_warning = '' def _compute_access_url(self): # Set the URL to reach the record on portal record.access_url = '#'
  • 54. ● Document - and App- specific portal url computation ● In your App ○ Portal Implementation... ○ access_token definition ○ Share button ● /mail/view controller check and redirection to portal class PortalMixin(models.AbstractModel): _name = "portal.mixin" access_url = fields.Char(compute='_compute_access_url') access_token = fields.Char('Security Token') access_warning = fields.Text(compute="_compute_access_warning") def _compute_access_warning(self): # Set a warning text if the record can't be shared access_warning = '' def _compute_access_url(self): # Set the URL to reach the record on portal record.access_url = '#' <header> <button name="%(portal.portal_share_action)d" string="Share" type="action" class="oe_highlight oe_read_only"/> </header>
  • 56. — Still Classy Cool Dev
  • 57.
  • 58. ● Characterize / filter messages ● Subtype definition (XML) ○ model specific (e.g. plant) ○ default / hidden ● Use in code: message_post class Plant(models.Model): _name = 'nursery.plant' _inherit = ['mail.thread'] def write(self, values):: res = super() if 'price' in values: self.message_post('Price Updated', subtype='plant_price') return res <record id="plant_price" model="mail.message.subtype"> <field name="name">Price Updated</field> <field name="res_model">nursery.plant</field> <field name="default" eval="True"/> <field name="hidden" eval="False"/> <field name="description">Price Updated</field> </record>
  • 59. ● Track value change ● track_visibility on field ○ onchange ○ Always ○ True ● Automatic logging class Plant(models.Model): _name = 'nursery.plant' _inherit = ['mail.thread'] price = fields.Float('Price', track_visibility=True)
  • 60. ● Warn on some specific value change ● Link a set of tracking and a subtype ○ _track_subtype ○ return xml_id ● Message with tracking generated with the subtype ○ allow people to be notified class Plant(models.Model): _name = 'nursery.plant' _inherit = ['mail.thread', 'rating.mixin'] price = fields.Float('Price', track_visibility='onchange') def _track_subtype(self, values): if 'price' in values: return 'plant_nursery.plant_price' return super()
  • 61. class Plant(models.Model): _name = 'nursery.plant' _inherit = ['mail.thread', 'rating.mixin'] price = fields.Float('Price', track_visibility='onchange') def _track_template(self, values): res = super() if 'price' in values: res['price'] = ( 'plant_price_template', options) return res ● Email on some specific value change ● Link a set of tracking and an automatic mailing ○ _track_template ○ give a mail.template and options ● Template rendered and sent ○ Force mailing to people ● Ultra power: add rating in template
  • 62. ● Email integrated with mailgateway ● Purpose: create / update thread in a given model ● Owner: record defining the alias ● Example ○ alias on category ○ creating XMas quote class MailAlias(models.AbstractModel): _name = 'mail.alias' name = fields.Char('Email') # record creation / update model = fields.Char('Model') thread_id = fields.Integer('Update specific record') # record owner parent_model = fields.Char('Owner model') parent_thread_id = fields.Integer('Owner ID')
  • 63. ● mail.alias.mixin ● add alias_id field ● Specify what do do with alias by overriding methods class Category(models.Model): _name = 'plant.category' _inherit = ['mail.alias.mixin'] def get_alias_model_name(self, values): return 'nursery.order' def get_alias_values(self): values = super() values['alias_defaults'] = {} return values class MailAlias(models.AbstractModel): _name = 'mail.alias.mixin' _inherit = {'mail.alias' : 'alias_id'} alias_id = fields.Many2one('Alias')
  • 64.
  • 66. #odooexperience Based on work from Thibault DELAVALLEE and Martin TRIGAUX, that was based on work from Damien BOUVY https://github.com/tivisse/odoodays-2018 EXPERIENCE 2018