diff options
| -rw-r--r-- | addons/note/data/note_data.xml | 4 | ||||
| -rw-r--r-- | addons/note/data/note_demo.xml | 4 | ||||
| -rw-r--r-- | addons/note/models/note.py | 221 | ||||
| -rw-r--r-- | addons/note/models/res_users.py | 29 | ||||
| -rw-r--r-- | addons/note/security/note_security.xml | 6 | ||||
| -rw-r--r-- | addons/note/tests/__init__.py | 2 | ||||
| -rw-r--r-- | addons/note/tests/test_note.py | 18 | ||||
| -rw-r--r-- | addons/note/views/note_templates.xml | 6 | ||||
| -rw-r--r-- | addons/note/views/note_views.xml | 57 |
9 files changed, 162 insertions, 185 deletions
diff --git a/addons/note/data/note_data.xml b/addons/note/data/note_data.xml index 376b8e9053f..292dc9487b8 100644 --- a/addons/note/data/note_data.xml +++ b/addons/note/data/note_data.xml @@ -1,5 +1,5 @@ <?xml version="1.0"?> -<openerp> +<odoo> <data> <record model="note.stage" id="note_stage_00"> @@ -33,4 +33,4 @@ </record> </data> -</openerp> +</odoo> diff --git a/addons/note/data/note_demo.xml b/addons/note/data/note_demo.xml index 393eb171bf3..d1da29b0e65 100644 --- a/addons/note/data/note_demo.xml +++ b/addons/note/data/note_demo.xml @@ -1,5 +1,5 @@ <?xml version="1.0"?> -<openerp> +<odoo> <data noupdate="1"> <record model="note.stage" id="demo_note_stage_01"> <field name="name">Today</field> @@ -107,4 +107,4 @@ </record> </data> -</openerp> +</odoo> diff --git a/addons/note/models/note.py b/addons/note/models/note.py index 8ac934cb1c0..e1908c68c18 100644 --- a/addons/note/models/note.py +++ b/addons/note/models/note.py @@ -1,130 +1,98 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from openerp import _, SUPERUSER_ID -from openerp.osv import osv, fields -from openerp.tools import html2plaintext +from odoo import api, fields, models +from odoo.tools import html2plaintext + + +class Stage(models.Model): -class note_stage(osv.osv): - """ Category of Note """ _name = "note.stage" _description = "Note Stage" - _columns = { - 'name': fields.char('Stage Name', translate=True, required=True), - 'sequence': fields.integer('Sequence', help="Used to order the note stages"), - 'user_id': fields.many2one('res.users', 'Owner', help="Owner of the note stage.", required=True, ondelete='cascade'), - 'fold': fields.boolean('Folded by Default'), - } - _order = 'sequence asc' - _defaults = { - 'fold': 0, - 'user_id': lambda self, cr, uid, ctx: uid, - 'sequence' : 1, - } - -class note_tag(osv.osv): + _order = 'sequence' + + name = fields.Char('Stage Name', translate=True, required=True) + sequence = fields.Integer(help="Used to order the note stages", default=1) + user_id = fields.Many2one('res.users', string='Owner', required=True, ondelete='cascade', default=lambda self: self.env.uid, help="Owner of the note stage") + fold = fields.Boolean('Folded by Default') + + +class Tag(models.Model): + _name = "note.tag" _description = "Note Tag" - _columns = { - 'name': fields.char('Tag Name', required=True), - 'color': fields.integer('Color Index'), - } + + name = fields.Char('Tag Name', required=True) + color = fields.Integer('Color Index') + _sql_constraints = [ - ('name_uniq', 'unique (name)', "Tag name already exists !"), + ('name_uniq', 'unique (name)', "Tag name already exists !"), ] -class note_note(osv.osv): - """ Note """ + +class Note(models.Model): + _name = 'note.note' _inherit = ['mail.thread'] _description = "Note" - - #writing method (no modification of values) - def name_create(self, cr, uid, name, context=None): - rec_id = self.create(cr, uid, {'memo': name}, context=context) - return self.name_get(cr, uid, [rec_id], context)[0] - - #read the first line (convert hml into text) - def _get_note_first_line(self, cr, uid, ids, name="", args={}, context=None): - res = {} - for note in self.browse(cr, uid, ids, context=context): - res[note.id] = (note.memo and html2plaintext(note.memo) or "").strip().replace('*','').split("\n")[0] - - return res - - def onclick_note_is_done(self, cr, uid, ids, context=None): - return self.write(cr, uid, ids, {'open': False, 'date_done': fields.date.today()}, context=context) - - def onclick_note_not_done(self, cr, uid, ids, context=None): - return self.write(cr, uid, ids, {'open': True}, context=context) - - #return the default stage for the uid user - def _get_default_stage_id(self,cr,uid,context=None): - ids = self.pool.get('note.stage').search(cr,uid,[('user_id','=',uid)], context=context) - return ids and ids[0] or False - - def _set_stage_per_user(self, cr, uid, id, name, value, args=None, context=None): - note = self.browse(cr, uid, id, context=context) - if not value: return False - stage_ids = [value] + [stage.id for stage in note.stage_ids if stage.user_id.id != uid ] - return self.write(cr, uid, [id], {'stage_ids': [(6, 0, set(stage_ids))]}, context=context) - - def _get_stage_per_user(self, cr, uid, ids, name, args, context=None): - result = dict.fromkeys(ids, False) - for record in self.browse(cr, uid, ids, context=context): - for stage in record.stage_ids: - if stage.user_id.id == uid: - result[record.id] = stage.id - return result - - _columns = { - 'name': fields.function(_get_note_first_line, - string='Note Summary', - type='text', store=True), - 'user_id': fields.many2one('res.users', 'Owner'), - 'memo': fields.html('Note Content'), - 'sequence': fields.integer('Sequence'), - 'stage_id': fields.function(_get_stage_per_user, - fnct_inv=_set_stage_per_user, - string='Stage', - type='many2one', - relation='note.stage'), - 'stage_ids': fields.many2many('note.stage','note_stage_rel','note_id','stage_id','Stages of Users'), - 'open': fields.boolean('Active', track_visibility='onchange'), - 'date_done': fields.date('Date done'), - 'color': fields.integer('Color Index'), - 'tag_ids' : fields.many2many('note.tag','note_tags_rel','note_id','tag_id','Tags'), - } - _defaults = { - 'user_id': lambda self, cr, uid, ctx=None: uid, - 'open' : 1, - 'stage_id' : _get_default_stage_id, - } _order = 'sequence' - def read_group(self, cr, uid, domain, fields, groupby, offset=0, limit=None, context=None, orderby=False, lazy=True): - if groupby and groupby[0]=="stage_id": - - #search all stages - current_stage_ids = self.pool.get('note.stage').search(cr,uid,[('user_id','=',uid)], context=context) - - if current_stage_ids: #if the user have some stages - stages = self.pool['note.stage'].browse(cr, uid, current_stage_ids, context=context) - - result = [{ #notes by stage for stages user - '__context': {'group_by': groupby[1:]}, - '__domain': domain + [('stage_ids.id', '=', stage.id)], - 'stage_id': (stage.id, stage.name), - 'stage_id_count': self.search(cr,uid, domain+[('stage_ids', '=', stage.id)], context=context, count=True), - '__fold': stage.fold, - } for stage in stages] - - #note without user's stage - nb_notes_ws = self.search(cr,uid, domain+[('stage_ids', 'not in', current_stage_ids)], context=context, count=True) + def _get_default_stage_id(self): + return self.env['note.stage'].search([('user_id', '=', self.env.uid)], limit=1) + + name = fields.Text(compute='_compute_name', string='Note Summary', store=True) + user_id = fields.Many2one('res.users', string='Owner', default=lambda self: self.env.uid) + memo = fields.Html('Note Content') + sequence = fields.Integer('Sequence') + stage_id = fields.Many2one('note.stage', compute='_compute_stage_id', + inverse='_inverse_stage_id', default=_get_default_stage_id, string='Stage') + stage_ids = fields.Many2many('note.stage', 'note_stage_rel', 'note_id', 'stage_id', string='Stages of Users') + open = fields.Boolean(string='Active', track_visibility='onchange', default=True) + date_done = fields.Date('Date done') + color = fields.Integer(string='Color Index') + tag_ids = fields.Many2many('note.tag', 'note_tags_rel', 'note_id', 'tag_id', string='Tags') + + @api.depends('memo') + def _compute_name(self): + """ Read the first line of the memo to determine the note name """ + for note in self: + text = html2plaintext(note.memo) if note.memo else '' + note.name = text.strip().replace('*', '').split("\n")[0] + + @api.multi + def _compute_stage_id(self): + for note in self: + for stage in note.stage_ids.filtered(lambda stage: stage.user_id == self.env.user): + note.stage_id = stage + + @api.multi + def _inverse_stage_id(self): + for note in self.filtered('stage_id'): + note.stage_ids = note.stage_id + note.stage_ids.filtered(lambda stage: stage.user_id != self.env.user) + + @api.model + def name_create(self, name): + return self.create({'memo': name}).name_get()[0] + + @api.model + def read_group(self, domain, fields, groupby, offset=0, limit=None, orderby=False, lazy=True): + if groupby and groupby[0] == "stage_id": + stages = self.env['note.stage'].search([('user_id', '=', self.env.uid)]) + if stages: # if the user has some stages + result = [{ # notes by stage for stages user + '__context': {'group_by': groupby[1:]}, + '__domain': domain + [('stage_ids.id', '=', stage.id)], + 'stage_id': (stage.id, stage.name), + 'stage_id_count': self.search_count(domain + [('stage_ids', '=', stage.id)]), + '__fold': stage.fold, + } for stage in stages] + + # note without user's stage + nb_notes_ws = self.search_count(domain + [('stage_ids', 'not in', stages.ids)]) if nb_notes_ws: # add note to the first column if it's the first stage - dom_not_in = ('stage_ids', 'not in', current_stage_ids) - if result and result[0]['stage_id'][0] == current_stage_ids[0]: + dom_not_in = ('stage_ids', 'not in', stages.ids) + if result and result[0]['stage_id'][0] == stages[0].id: dom_in = result[0]['__domain'].pop() result[0]['__domain'] = domain + ['|', dom_in, dom_not_in] result[0]['stage_id_count'] += nb_notes_ws @@ -134,34 +102,37 @@ class note_note(osv.osv): '__context': {'group_by': groupby[1:]}, '__domain': domain + [dom_not_in], 'stage_id': (stages[0].id, stages[0].name), - 'stage_id_count':nb_notes_ws, + 'stage_id_count': nb_notes_ws, '__fold': stages[0].name, }] + result - - else: # if stage_ids is empty - - #note without user's stage - nb_notes_ws = self.search(cr,uid, domain, context=context, count=True) + else: # if stage_ids is empty, get note without user's stage + nb_notes_ws = self.search_count(domain) if nb_notes_ws: - result = [{ #notes for unknown stage + result = [{ # notes for unknown stage '__context': {'group_by': groupby[1:]}, '__domain': domain, 'stage_id': False, - 'stage_id_count':nb_notes_ws + 'stage_id_count': nb_notes_ws }] else: result = [] return result + return super(Note, self).read_group(domain, fields, groupby, offset=offset, limit=limit, orderby=orderby, lazy=lazy) - else: - return super(note_note, self).read_group(cr, uid, domain, fields, groupby, - offset=offset, limit=limit, context=context, orderby=orderby,lazy=lazy) - - def _notification_get_recipient_groups(self, cr, uid, ids, message, recipients, context=None): - res = super(note_note, self)._notification_get_recipient_groups(cr, uid, ids, message, recipients, context=context) - new_action_id = self.pool['ir.model.data'].xmlid_to_res_id(cr, uid, 'note.action_note_note') - new_action = self._notification_link_helper(cr, uid, ids, 'new', context=context, action_id=new_action_id) + @api.multi + def _notification_get_recipient_groups(self, message, recipients): + res = super(Note, self)._notification_get_recipient_groups(message, recipients) + new_action_id = self.env['ir.model.data'].xmlid_to_res_id('note.action_note_note') + new_action = self._notification_link_helper('new', action_id=new_action_id) res['user'] = { 'actions': [{'url': new_action, 'title': _('New Note')}] } return res + + @api.multi + def action_close(self): + return self.write({'open': False, 'date_done': fields.date.today()}) + + @api.multi + def action_open(self): + return self.write({'open': True}) diff --git a/addons/note/models/res_users.py b/addons/note/models/res_users.py index 006a2b77fd1..4cb4e3757c1 100644 --- a/addons/note/models/res_users.py +++ b/addons/note/models/res_users.py @@ -1,26 +1,21 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from openerp.osv import osv -from openerp import SUPERUSER_ID +from odoo import api, models -class res_users(osv.Model): +class Users(models.Model): _name = 'res.users' _inherit = ['res.users'] - def create(self, cr, uid, data, context=None): - user_id = super(res_users, self).create(cr, uid, data, context=context) - note_obj = self.pool['note.stage'] - data_obj = self.pool['ir.model.data'] - is_employee = self.has_group(cr, user_id, 'base.group_user') - if is_employee: - for n in range(5): - xmlid = 'note_stage_%02d' % (n,) - try: - _model, stage_id = data_obj.get_object_reference(cr, SUPERUSER_ID, 'note', xmlid) - except ValueError: - continue - note_obj.copy(cr, SUPERUSER_ID, stage_id, default={'user_id': user_id}, context=context) - return user_id + @api.model + def create(self, values): + user = super(Users, self).create(values) + # for new employee, create his own 5 base note stages + if user.has_group('base.group_user'): + for num in range(5): + stage = self.env.ref('note.note_stage_%02d' % (num,), raise_if_not_found=False) + if stage: + stage.sudo().copy(default={'user_id': user.id}) + return user diff --git a/addons/note/security/note_security.xml b/addons/note/security/note_security.xml index d57c105fba3..6463bbfab1b 100644 --- a/addons/note/security/note_security.xml +++ b/addons/note/security/note_security.xml @@ -1,6 +1,5 @@ <?xml version="1.0"?> -<openerp> -<data> +<odoo> <record id="note_note_rule_global" model="ir.rule"> <field name="name">Only followers can access a sticky notes</field> <field name="model_id" ref="model_note_note"/> @@ -26,5 +25,4 @@ <field name="global" eval="True"/> </record> -</data> -</openerp> +</odoo> diff --git a/addons/note/tests/__init__.py b/addons/note/tests/__init__.py index 9dcc9ac3390..b7120138853 100644 --- a/addons/note/tests/__init__.py +++ b/addons/note/tests/__init__.py @@ -1,4 +1,4 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from . import test_note +from . import test_note diff --git a/addons/note/tests/test_note.py b/addons/note/tests/test_note.py index 54b2d7b18af..124f45ca0af 100644 --- a/addons/note/tests/test_note.py +++ b/addons/note/tests/test_note.py @@ -1,25 +1,21 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from openerp.tests import common +from odoo.tests import common class TestNote(common.TransactionCase): def test_bug_lp_1156215(self): - """ensure any users can create new users""" - cr, uid = self.cr, self.uid - IMD = self.registry('ir.model.data') - Users = self.registry('res.users') + """ ensure any users can create new users """ + demo_user = self.env.ref('base.user_demo') + group_erp = self.env.ref('base.group_erp_manager') - _, demo_user = IMD.get_object_reference(cr, uid, 'base', 'user_demo') - _, group_id = IMD.get_object_reference(cr, uid, 'base', 'group_erp_manager') - - Users.write(cr, uid, [demo_user], { - 'groups_id': [(4, group_id)], + demo_user.write({ + 'groups_id': [(4, group_erp.id)], }) # must not fail - Users.create(cr, demo_user, { + demo_user.create({ 'name': 'test bug lp:1156215', 'login': 'lp_1156215', }) diff --git a/addons/note/views/note_templates.xml b/addons/note/views/note_templates.xml index b685078acc9..dcdc6e5cd95 100644 --- a/addons/note/views/note_templates.xml +++ b/addons/note/views/note_templates.xml @@ -1,10 +1,8 @@ <?xml version="1.0" encoding="utf-8"?> -<openerp> - <data> +<odoo> <template id="assets_backend" name="note assets" inherit_id="web.assets_backend"> <xpath expr="." position="inside"> <link rel="stylesheet" href="/note/static/src/css/note.css"/> </xpath> </template> - </data> -</openerp> +</odoo> diff --git a/addons/note/views/note_views.xml b/addons/note/views/note_views.xml index 693f6792c28..c04c40ca810 100644 --- a/addons/note/views/note_views.xml +++ b/addons/note/views/note_views.xml @@ -1,8 +1,7 @@ <?xml version="1.0"?> -<openerp> - <data> +<odoo> <!-- note Stage Form View --> - <record model="ir.ui.view" id="view_note_stage_form"> + <record id="view_note_stage_form" model="ir.ui.view"> <field name="name">note.stage.form</field> <field name="model">note.stage</field> <field name="arch" type="xml"> @@ -15,7 +14,7 @@ </record> <!-- note Stage Tree View --> - <record model="ir.ui.view" id="view_note_stage_tree"> + <record id="view_note_stage_tree" model="ir.ui.view"> <field name="name">note.stage.tree</field> <field name="model">note.stage</field> <field name="field_parent"></field> @@ -29,7 +28,7 @@ </record> <!-- note Stage Action --> - <record model="ir.actions.act_window" id="action_note_stage"> + <record id="action_note_stage" model="ir.actions.act_window"> <field name="name">Stages</field> <field name="res_model">note.stage</field> <field name="view_mode">tree,form</field> @@ -61,9 +60,8 @@ </field> </record> - <!-- New note Kanban View --> - <record model="ir.ui.view" id="view_note_note_kanban"> + <record id="view_note_note_kanban" model="ir.ui.view"> <field name="name">note.note.kanban</field> <field name="model">note.note</field> <field name="arch" type="xml"> @@ -94,8 +92,8 @@ </ul> </div> <span> - <a name="onclick_note_is_done" type="object" t-if="record.open.raw_value"><i class="fa fa-check"/></a> - <a name="onclick_note_not_done" type="object" t-if="!record.open.raw_value"><i class="fa fa-undo"/></a> + <a name="action_close" type="object" t-if="record.open.raw_value"><i class="fa fa-check"/></a> + <a name="action_open" type="object" t-if="!record.open.raw_value"><i class="fa fa-undo"/></a> </span> <!-- kanban note --> <span t-attf-class="oe_kanban_content #{record.open.raw_value ? '' : 'note_text_line_through'}"> @@ -117,7 +115,7 @@ </record> <!-- New note Tree View --> - <record model="ir.ui.view" id="view_note_note_tree"> + <record id="view_note_note_tree" model="ir.ui.view"> <field name="name">note.note.tree</field> <field name="model">note.note</field> <field name="arch" type="xml"> @@ -131,7 +129,7 @@ </record> <!-- New note Form View --> - <record model="ir.ui.view" id="view_note_note_form"> + <record id="view_note_note_form" model="ir.ui.view"> <field name="name">note.note.form</field> <field name="model">note.note</field> <field name="arch" type="xml"> @@ -152,7 +150,7 @@ </record> <!-- Search note --> - <record model="ir.ui.view" id="view_note_note_filter"> + <record id="view_note_note_filter" model="ir.ui.view"> <field name="name">note.note.search</field> <field name="model">note.note</field> <field name="arch" type="xml"> @@ -169,7 +167,7 @@ </record> <!-- Action --> - <record model="ir.actions.act_window" id="action_note_note"> + <record id="action_note_note" model="ir.actions.act_window"> <field name="name">Notes</field> <field name="res_model">note.note</field> <field name="view_type">form</field> @@ -192,10 +190,31 @@ </field> </record> - <menuitem name="Notes" id="menu_note_notes" sequence="3" action="note.action_note_note" web_icon="note,static/description/icon.png"/> - <menuitem name="Configuration" id="menu_note_configuration" sequence="100" parent="menu_note_notes" groups="base.group_no_one"/> - <menuitem name="Stages" id="menu_notes_stage" parent="menu_note_configuration" action="note.action_note_stage" sequence="21" /> - <menuitem id="notes_tag_menu" parent="menu_note_configuration" action="note_tag_action" sequence="22"/> + <menuitem + id="menu_note_notes" + name="Notes" + sequence="3" + action="note.action_note_note" + web_icon="note,static/description/icon.png"/> + + <menuitem + id="menu_note_configuration" + name="Configuration" + sequence="100" + parent="menu_note_notes" + groups="base.group_no_one"/> + + <menuitem + id="menu_notes_stage" + name="Stages" + parent="menu_note_configuration" + action="note.action_note_stage" + sequence="21"/> + + <menuitem + id="notes_tag_menu" + parent="menu_note_configuration" + action="note_tag_action" + sequence="22"/> - </data> -</openerp> +</odoo> |
