소스 검색

Odoo-Nuxeo Integration module

Riyaj Pathan 8 년 전
부모
커밋
75e23d0709

+ 9 - 0
nuxeoconnect/__init__.py

@@ -0,0 +1,9 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+#    Odoo, Open Source Management Solution
+#    Copyright (C) 2016 Prime Consulting SA, Cape Verde (<http://prime.cv>).
+#
+##############################################################################
+
+from . import models

+ 35 - 0
nuxeoconnect/__manifest__.py

@@ -0,0 +1,35 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+#    Odoo, Open Source Management Solution
+#    Copyright (C) 2016 Prime Consulting SA, Cape Verde (<http://prime.cv>).
+#
+##############################################################################
+
+{
+    'name': 'Nuxeo Integration',
+    'version': '10.0.0.1',
+    'category': 'API',
+    'summary': 'Nuxeo - Odoo Integration',
+    'description': """
+###########################################
+		Nuxeo - Odoo Integration
+###########################################		
+    """,
+    'author': 'Prime Consulting SA',
+    'website': 'www.prime.cv',
+    'depends': ['base'],
+    'data': [                
+                'data/nuxeo_data.xml',
+
+    			'views/nuxeo.xml',
+                'views/ir_attachment.xml',            
+
+                'security/ir.model.access.csv',
+            ],
+    'external_dependencies': {'python': ['nuxeo']},
+    'installable': True,
+    'auto_install': False,
+    'application': True,
+    'sequence': 1,
+}

+ 23 - 0
nuxeoconnect/data/nuxeo_data.xml

@@ -0,0 +1,23 @@
+<odoo>
+	<data noupdate="1">
+
+		<record id="nuxeo_settings_default" model="nuxeo.settings">
+			<field name="url">https://your_nuxeo_url/nuxeo/</field>
+			<field name="login">test</field>			
+		</record>
+
+		<record forcecreate="True" id="nuxeo_upload_document_bulk_scheduler" model="ir.cron">
+			<field name="name">Upload non-synced documents/attachments to Nuxeo Server - Bulk upload</field>
+	        <field eval="True" name="active" />
+	        <field name="user_id" ref="base.user_root" />
+	        <field name="interval_number">1</field>
+	        <field name="interval_type">days</field>
+	        <field name="numbercall">-1</field>
+	        <field eval="False" name="doall" />
+	        <field eval="'ir.attachment'" name="model" />
+	        <field eval="'nuxeo_upload_document_bulk'" name="function" />
+	        <field eval="'()'" name="args" />
+		</record>
+
+	</data>
+</odoo>

+ 5 - 0
nuxeoconnect/models/__init__.py

@@ -0,0 +1,5 @@
+# -*- coding: utf-8 -*-
+
+from . import res_nuxeo
+from . import res_users
+from . import ir_attachment

+ 60 - 0
nuxeoconnect/models/ir_attachment.py

@@ -0,0 +1,60 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+#    Odoo, Open Source Management Solution
+#    Copyright (C) 2016 Prime Consulting SA, Cape Verde (<http://prime.cv>).
+#
+##############################################################################
+
+from odoo import models, api, fields
+from odoo import SUPERUSER_ID
+from odoo.exceptions import ValidationError, UserError
+from odoo.tools.translate import _
+
+import logging
+_logger = logging.getLogger(__name__)
+
+class IrAttachment(models.Model):
+    _inherit = 'ir.attachment'
+
+    nuxeo_document_id = fields.Char('Nuxeo Document Id')
+    type = fields.Selection([('url', 'URL'), ('binary', 'File'), ('nuxeo', 'Nuxeo')],
+                            string='Type', required=True, default='binary', change_default=True,
+                            help="You can either upload a file from your computer or copy/paste an internet link to your file.")
+
+    @api.model
+    def create(self, vals):
+        attachment = super(IrAttachment, self).create(vals)
+        for rec in attachment:
+            #upload document to Nuxeo:
+            conn = self.create_uid.get_nuxeo_connection()
+            if conn and rec.datas:
+                rec.create_uid.nuxeo_upload_document(conn, rec)
+        return attachment
+
+    @api.depends('store_fname', 'db_datas')
+    def _compute_datas(self):
+        """get document blob from Nuxeo Document Id to show document/attachment in Odoo.
+        """
+        for attach in self:        	
+            if attach.type == 'nuxeo':
+                document_id = attach.nuxeo_document_id
+                conn = attach.create_uid.get_nuxeo_connection()
+                blob = False
+                if conn and document_id:
+                    blob = attach.create_uid.nuxeo_fetch_document(conn, document_id)
+                attach.datas = blob
+            else:
+        		return super(IrAttachment, self)._compute_datas()
+
+    @api.multi
+    def nuxeo_upload_document_bulk(self):
+        """Scheduler function to upload documents/attachments not already synced to Nuxeo.
+        """
+        _logger.info("Scheduler started : Upload non-synced documents/attachments to Nuxeo Server - Bulk upload")
+        attachments = self.search(['|', ('type', '!=', 'nuxeo'), ('nuxeo_document_id', '=', False)])
+        conn = self.env['res.users'].browse(SUPERUSER_ID).create_uid.get_nuxeo_connection()
+        for attach in attachments:
+            if conn and attach.datas:
+                attach.create_uid.nuxeo_upload_document(conn, attach)
+        return True

+ 80 - 0
nuxeoconnect/models/res_nuxeo.py

@@ -0,0 +1,80 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+#    Odoo, Open Source Management Solution
+#    Copyright (C) 2016 Prime Consulting SA, Cape Verde (<http://prime.cv>).
+#
+##############################################################################
+
+from odoo import models, api, fields
+from odoo.exceptions import ValidationError
+from odoo.tools.translate import _
+import logging
+_logger = logging.getLogger(__name__)
+
+from nuxeo.nuxeo import Nuxeo as nx
+
+def nuxeo_connection(url=False, login=False, password=False):
+    """Nuxeo Server Connection
+    :param url: Nuxeo Server URL
+    :param login: Nuxeo server user id
+    :param password: Nuxeo server user password
+
+    :returns : True or False based on Authentication.
+    """
+    try:
+        conn = nx(
+                    base_url=url, 
+                    auth={
+                            'username': login,
+                            'password': password
+                    })
+        connection = conn.login()
+        return (True, True, conn)
+    except Exception, e:
+        return (False, e, False)
+
+
+class NuxeoSettings(models.Model):
+    _name = "nuxeo.settings"
+    _description = "Nuxeo Settings"
+
+    name = fields.Char("Name", default='Nuxeo Server Settings')
+    url = fields.Char('Nuxeo URL')
+    login = fields.Char('Login Id')
+    password = fields.Char('Password')
+    user_id = fields.Many2one('res.users', 'User', default=lambda self: self.env.user.id)
+
+    @api.multi
+    def unlink(self):
+        raise ValidationError('Error!\n\nYou do not have access to delete this document.\nPlease contact your administrator.')
+        
+    @api.multi
+    def action_test_connection(self):
+        for rec in self:
+            context = rec._context or {}
+            result = ''
+            connection = nuxeo_connection(rec.url, rec.login, rec.password)
+            nx_conn = connection[2]
+            if connection[0] is False:
+                result = 'Connection to Nuxeo Server failed! Please check Nuxeo Server Settings.\nError Details:\n%s'%(connection[1])
+            if connection[0] is True:
+                result = 'Connection to Nuxeo server successfully established.'
+                #create Odoo users as Nuxeo Users
+            	users = self.env['res.users'].search([('id', '>', 0)])
+            	for user in users:
+            		user.nuxeo_user_create(nx_conn)                
+                #check Filestore directory in Nuxeo:
+                user.nuxeo_filestore_directory_check(nx_conn)
+            if context and 'show_message' in context:
+                raise ValidationError(result)
+        return True
+
+    def nuxeo_connection(self=None, url=False, login=False, password=False):
+        connection = nuxeo_connection(url, login, password)
+        if connection[0] is False:
+            _logger.error('Connection to Nuxeo Server failed! Please check Nuxeo Server Settings.\nError Details:\n%s'%(connection[1]))
+        if connection[0] is True:
+            _logger.info('Connection to Nuxeo server successfully established.')
+        return connection
+

+ 210 - 0
nuxeoconnect/models/res_users.py

@@ -0,0 +1,210 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+#    Odoo, Open Source Management Solution
+#    Copyright (C) 2016 Prime Consulting SA, Cape Verde (<http://prime.cv>).
+#
+##############################################################################
+
+from odoo import models, api, fields
+from odoo.exceptions import ValidationError, UserError
+from odoo.tools.translate import _
+
+import logging
+_logger = logging.getLogger(__name__)
+
+import base64
+from nuxeo.nuxeo import Nuxeo as nx
+from nuxeo.blob import BufferBlob
+
+class Users(models.Model):
+    _inherit = "res.users"
+
+    @api.model
+    def create(self, vals):
+        """Create Nuxeo User on creating new Odoo User
+        """
+        user = super(Users, self).create(vals)
+        #conn = user.get_nuxeo_connection()
+        #user.nuxeo_user_create(conn)
+        return user
+
+    @api.multi
+    def write(self, vals):
+        for user in self:
+            user_login = user.login
+            
+            res = super(Users, self).write(vals)
+
+            newlogin = vals.get('login', False)
+            password = vals.get('password', False)
+            #if newlogin or password:
+            #        conn = user.get_nuxeo_connection()
+            #        user.nuxeo_user_update(conn, user_login, newlogin, password)
+        return res
+
+
+    @api.multi
+    def unlink(self):
+        #for user in self:
+            #conn = user.get_nuxeo_connection()
+            #user.nuxeo_user_delete(conn)
+        return super(Users, self).unlink()
+
+#####################################
+#            Nuxeo API Calls        #
+#####################################
+
+    @api.multi
+    def get_nuxeo_connection(self):
+        """ Nuxeo Server Connection 
+        """
+        nuxeo_settings = self.env['nuxeo.settings'].search([('id', '>', 0)], order="create_date asc", limit=1)
+        for nx_setting in nuxeo_settings:
+            url = nx_setting.url
+            login = nx_setting.login
+            password = nx_setting.password
+            conn = nx_setting.nuxeo_connection(url, login, password)[2]
+            return conn
+
+    @api.multi
+    def nuxeo_user_create(self, conn=False):
+        """Odoo User - Nuxeo User link
+        :param user: Odoo User
+        :var username: login(Odoo) <=> username(Nuxeo)
+
+        """
+        if conn:
+            for user in self:
+                login = user.login
+                try:
+                    nx_user = conn.users().fetch(login)
+                except Exception: #Odoo User don't exist in Nuxeo : Create Nuxeo User
+                    username = user.name.split(' ')
+                    args = {
+                            'lastName': username[-1], 
+                            'firstName': username[0], 
+                            'username': login, 
+                            'company': user.company_id.name,
+                            'password': user.password
+                            }
+                    nx_user = conn.users().create(args)
+                    _logger.info("User created on Nuxeo Server. Username: %s"%(' '.join([args['firstName'], args['lastName']])))
+        return True
+
+    @api.multi
+    def nuxeo_user_update(self, conn=False, login=False, newlogin=False, password=False):
+        """On updating Odoo User's login/password, update login/password for related Nuxeo user
+        """
+        if conn:
+            for user in self:
+                try:
+                    nx_user = conn.users().fetch(login)
+                    if nx_user:
+                        if newlogin:
+                            nx_user.properties['username'] = newlogin
+                            nx_user.save()
+                        if password:
+                            nx_user.properties['password'] = password
+                            nx_user.save()
+                        _logger.info("User information updated on Nuxeo Server.")
+                except Exception, e:
+                    raise ValidationError('Connection to Nuxeo Server Failed! \nError Details:\n%s'%(e))
+        return True
+
+
+
+    @api.multi
+    def nuxeo_user_delete(self, conn=False):
+        """On Deleteing Odoo User, update related Nuxeo User first name
+        """
+        if conn:
+            for user in self:
+                login = user.login
+                try:
+                    nx_user = conn.users().fetch(login)
+                    nx_user.properties['firstName'] = str(nx_user.properties['firstName']) + ' (deleted)'
+                    nx_user.save()
+                    nx_user.properties['username'] = False
+                    nx_user.save()
+                except Exception:
+                    pass
+        return True
+
+    @api.multi
+    def nuxeo_filestore_directory_check(self, conn=False):
+        _logger.info("Checking Filestore directory exists or not.")
+        dbname = str(self.env.cr.dbname)
+        upload_dir = 'Filestore_%s'%(dbname)
+        odooDir = {
+                    'entity-type': 'document',
+                    'name': 'Odoo',
+                    'type':'Folder', 
+                    'properties': {'dc:title': 'Odoo'}
+                    }
+        filestoreDir = {
+                    'entity-type': 'document',
+                    'name': upload_dir,
+                    'type':'Folder', 
+                    'properties': {'dc:title': upload_dir}
+                    }
+        if conn:
+            try:
+                conn.repository().fetch('/default-domain/workspaces/Odoo') 
+                _logger.info('"Odoo" directory already exists in Workspaces.')
+            except Exception:#create directory "Odoo"
+                repo = conn.repository(schemas=['dublincore']) 
+                repo.create('/default-domain/workspaces/', odooDir)
+                _logger.info('New Directory "Odoo" created in Workspaces.')
+
+            try:
+                conn.repository().fetch('/default-domain/workspaces/Odoo/' + upload_dir) 
+                _logger.info('"%s" directory already exists in Workspaces.'%(upload_dir))
+            except Exception:#create directory "Filestore_dbname"
+                repo = conn.repository(schemas=['dublincore']) 
+                repo.create('/default-domain/workspaces/Odoo/', filestoreDir)
+                _logger.info('New Directory "%s" created in Workspaces.'%(upload_dir))
+        return True
+
+
+    @api.multi
+    def nuxeo_upload_document(self, conn=False, attachment=False):
+        newDoc = {
+                    'name': 'Document',
+                    'type': 'File',
+                    'properties': {'dc:title': attachment.name}
+                }
+
+        filename = attachment.datas_fname
+        if not filename:
+            filename = str(attachment._name) + '.' + str(attachment.id)
+
+        filestoreDir = 'Filestore_' + str(self.env.cr.dbname)
+        try:
+            conn.repository().fetch('/default-domain/workspaces/Odoo/' + filestoreDir) 
+        except Exception, e:
+            self.nuxeo_filestore_directory_check(conn)
+
+        try:            
+            repo = conn.repository(schemas=['dublincore']) 
+            doc = repo.create('/default-domain/workspaces/Odoo/' + filestoreDir, newDoc)
+            file_content = base64.b64decode(attachment.datas)
+            blob = BufferBlob(file_content, filename, attachment.mimetype)
+            blob = conn.batch_upload().upload(blob)
+            doc.properties["file:content"] = blob
+            doc.save()
+            document_id = doc.get_id()
+            _logger.info("Document Successfully Uploaded to Nuxeo Server. File: %s Document id: %s"%(filename, document_id))
+            attachment.write({'nuxeo_document_id': document_id, 'type': 'nuxeo'})
+        except Exception, e:
+            _logger.warn("Document Upload to Nuxeo server Failed!!!\nError : %s"%(e))
+        return True
+
+
+    @api.multi
+    def nuxeo_fetch_document(self, conn=False, document_id=False):
+        if conn and document_id:
+            doc = conn.repository().fetch(document_id)
+            if doc:
+                return base64.b64encode(doc.fetch_blob())
+        return False

+ 2 - 0
nuxeoconnect/security/ir.model.access.csv

@@ -0,0 +1,2 @@
+id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
+access_nuxeo_settings_all,nuxeo.settings.all,model_nuxeo_settings,base.group_user,1,0,0,0

BIN
nuxeoconnect/static/description/icon.png


+ 23 - 0
nuxeoconnect/views/ir_attachment.xml

@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<odoo>
+        <!-- Attachment extension for Nuxeo Document Id field -->
+        <record id="view_attachment_form_nuxeo" model="ir.ui.view">
+        	<field name="name">ir.attachment.nuxeo</field>
+            <field name="model">ir.attachment</field>
+            <field name="inherit_id" ref="base.view_attachment_form"/>
+            <field name="arch" type="xml">
+            	<field name="datas" position="replace">
+            		<field name="datas" filename="datas_fname" attrs="{'invisible':[('type','!=','binary')]}"/>
+            	</field>
+            	<field name="url" position="replace">
+            		<field name="url" widget="url" attrs="{'invisible':[('type','!=','url')]}"/>
+            	</field>
+            	
+            	<field name="url" position="after">
+            		<field name="nuxeo_document_id" attrs="{'invisible':[('type','!=','nuxeo')]}"/>
+            	</field>
+            	
+            </field>
+        </record>
+
+</odoo>

+ 61 - 0
nuxeoconnect/views/nuxeo.xml

@@ -0,0 +1,61 @@
+<odoo>
+	<data>
+
+		<menuitem id="menu_technical_nuxeo"
+			name="Nuxeo"
+			parent="base.menu_custom"
+			groups="base.group_no_one"
+			sequence="1"/>
+
+
+		<record id="nuxeo_settings_form" model="ir.ui.view">
+			<field name="name">nuxeo.settings.form</field>
+			<field name="model">nuxeo.settings</field>
+			<field name="arch" type="xml">
+				<form string="Nuxeo Settings">
+					<sheet>
+						<h1>
+							<field name="name" readonly="1"/>
+						</h1>
+						<group>
+							<field name="url" colspan="2" required="1"/>
+							<field name="login" colspan="2" required="1"/>
+							<field name="password" colspan="2" password="1" required="1"/>
+						</group>
+					</sheet>
+					<footer>
+						<button name="action_test_connection" string="Test Connection" type="object" class="oe_highlight"/>
+						<button name="cancel" special="cancel" string="Close" class="oe_link"/>
+					</footer>
+				</form>
+			</field>
+		</record>
+
+		<record id="nuxeo_settings_tree" model="ir.ui.view">
+			<field name="name">nuxeo.settings.tree</field>
+			<field name="model">nuxeo.settings</field>
+			<field name="arch" type="xml">
+				<tree string="Nuxeo Settings" create="0" no_create="1" delete="0">
+					<field name="url"/>
+					<field name="login"/>
+				</tree>
+			</field>
+		</record>
+
+		<record id="action_nuxeo_settings" model="ir.actions.act_window">
+			<field name="name">Nuxeo Settings</field>
+			<field name="res_model">nuxeo.settings</field>
+			<field name="view_type">form</field>
+			<field name="view_mode">form</field>
+			<field name="res_id" ref="nuxeo_settings_default"/>
+			<field name="target">new</field>
+			<field name="context">{'show_message': True}</field>
+		</record>
+
+		<menuitem id="menu_nuxeo_settings"
+			name="Nuxeo Settings"
+			parent="nuxeoconnect.menu_technical_nuxeo"
+			action="action_nuxeo_settings"/>
+
+	</data>
+</odoo>