diff --git a/report_relatorio/README.rst b/report_relatorio/README.rst
new file mode 100644
index 0000000..215ef82
--- /dev/null
+++ b/report_relatorio/README.rst
@@ -0,0 +1,89 @@
+.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
+ :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
+ :alt: License: AGPL-3
+
+================
+Base report xlsx
+================
+
+This module provides a basic report class to generate xlsx report.
+
+Installation
+============
+
+Make sure you have ``xlsxwriter`` Python module installed::
+
+$ pip install xlsxwriter
+
+Usage
+=====
+
+An example of XLSX report for partners:
+
+A python class ::
+
+ from openerp.addons.report_xlsx.report.report_xlsx import ReportXlsx
+
+ class partner_xlsx(ReportXlsx):
+
+ def generate_xlsx_report(self, workbook, data, partners):
+ for obj in partners:
+ report_name = obj.name
+ # One sheet by partner
+ sheet = workbook.add_worksheet(report_name[:31])
+ bold = workbook.add_format({'bold': True})
+ sheet.write(0, 0, obj.name, bold)
+
+
+ partner_xlsx('report.res.partner.xlsx',
+ 'res.partner')
+
+To manipulate the ``workbook`` and ``sheet`` objects, refer to the
+`documentation `_ of ``xlsxwriter``.
+
+A report XML record ::
+
+
+
+.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas
+ :alt: Try me on Runbot
+ :target: https://runbot.odoo-community.org/runbot/143/8.0
+
+Bug Tracker
+===========
+
+Bugs are tracked on `GitHub Issues `_.
+In case of trouble, please check there if your issue has already been reported.
+If you spotted it first, help us smashing it by providing a detailed and welcomed feedback
+`here `_.
+
+Credits
+=======
+
+* Icon taken from http://www.icons101.com/icon/id_67712/setid_2096/Boxed_Metal_by_Martin/xlsx.
+
+Contributors
+------------
+
+* Adrien Peiffer
+
+Maintainer
+----------
+
+.. image:: https://odoo-community.org/logo.png
+ :alt: Odoo Community Association
+ :target: https://odoo-community.org
+
+This module is maintained by the OCA.
+
+OCA, or the Odoo Community Association, is a nonprofit organization whose mission is to support the collaborative development of Odoo features and promote its widespread use.
+
+To contribute to this module, please visit https://odoo-community.org.
diff --git a/report_relatorio/__init__.py b/report_relatorio/__init__.py
new file mode 100644
index 0000000..6db3fc7
--- /dev/null
+++ b/report_relatorio/__init__.py
@@ -0,0 +1,19 @@
+# -*- coding: utf-8 -*-
+
+# Copyright 2016 Fabien Bourgeois
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
+from . import models
+from . import report
diff --git a/report_relatorio/models/__init__.py b/report_relatorio/models/__init__.py
new file mode 100644
index 0000000..1a293ad
--- /dev/null
+++ b/report_relatorio/models/__init__.py
@@ -0,0 +1,18 @@
+# -*- coding: utf-8 -*-
+
+# Copyright 2016 Fabien Bourgeois
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
+from . import ir_report
diff --git a/report_relatorio/models/ir_report.py b/report_relatorio/models/ir_report.py
new file mode 100644
index 0000000..23f370e
--- /dev/null
+++ b/report_relatorio/models/ir_report.py
@@ -0,0 +1,24 @@
+# -*- coding: utf-8 -*-
+
+# Copyright 2016 Fabien Bourgeois
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
+from openerp import fields, models
+
+
+class IrActionsReportRelatorio(models.Model):
+ _inherit = 'ir.actions.report.xml'
+
+ report_type = fields.Selection(selection_add=[("xlsx", "xlsx")])
diff --git a/report_relatorio/openerp.tmp.py b/report_relatorio/openerp.tmp.py
new file mode 100644
index 0000000..d061330
--- /dev/null
+++ b/report_relatorio/openerp.tmp.py
@@ -0,0 +1,30 @@
+# -*- coding: utf-8 -*-
+
+# Copyright 2016 Fabien Bourgeois
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
+{
+ 'name': 'Relatorio reporting',
+ 'summary': 'Adds simple reporting engine based on relatorio',
+ 'version': '0.1',
+ 'category': 'Reporting',
+ 'author': 'Fabien Bourgeois',
+ 'website': 'http://www.yaltik.com',
+ 'license': 'AGPL-3',
+ 'application': True,
+ 'installable': True,
+ 'external_dependencies': {'python': ['relatorio']},
+ 'depends': ['base']
+}
diff --git a/report_relatorio/report/__init__.py b/report_relatorio/report/__init__.py
new file mode 100644
index 0000000..637f86d
--- /dev/null
+++ b/report_relatorio/report/__init__.py
@@ -0,0 +1,18 @@
+# -*- coding: utf-8 -*-
+
+# Copyright 2016 Fabien Bourgeois
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
+from . import report_relatorio
diff --git a/report_relatorio/report/report_xlsx.py b/report_relatorio/report/report_xlsx.py
new file mode 100644
index 0000000..285c97b
--- /dev/null
+++ b/report_relatorio/report/report_xlsx.py
@@ -0,0 +1,45 @@
+# -*- coding: utf-8 -*-
+# Copyright 2015 ACSONE SA/NV ()
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
+
+from cStringIO import StringIO
+
+from openerp.report.report_sxw import report_sxw
+from openerp.api import Environment
+
+import logging
+_logger = logging.getLogger(__name__)
+
+try:
+ import xlsxwriter
+except ImportError:
+ _logger.debug('Can not import xlsxwriter`.')
+
+
+class ReportXlsx(report_sxw):
+
+ def create(self, cr, uid, ids, data, context=None):
+ self.env = Environment(cr, uid, context)
+ report_obj = self.env['ir.actions.report.xml']
+ report = report_obj.search([('report_name', '=', self.name[7:])])
+ if report.ids:
+ self.title = report.name
+ if report.report_type == 'xlsx':
+ return self.create_xlsx_report(ids, data, report)
+ return super(ReportXlsx, self).create(cr, uid, ids, data, context)
+
+ def create_xlsx_report(self, ids, data, report):
+ self.parser_instance = self.parser(
+ self.env.cr, self.env.uid, self.name2, self.env.context)
+ objs = self.getObjects(
+ self.env.cr, self.env.uid, ids, self.env.context)
+ self.parser_instance.set_context(objs, data, ids, 'xlsx')
+ file_data = StringIO()
+ workbook = xlsxwriter.Workbook(file_data)
+ self.generate_xlsx_report(workbook, data, objs)
+ workbook.close()
+ file_data.seek(0)
+ return (file_data.read(), 'xlsx')
+
+ def generate_xlsx_report(self, workbook, data, objs):
+ raise NotImplementedError()
diff --git a/report_relatorio/static/description/icon.png b/report_relatorio/static/description/icon.png
new file mode 100644
index 0000000..baab9a4
Binary files /dev/null and b/report_relatorio/static/description/icon.png differ
diff --git a/web_image_uploader/__init__.py b/web_image_uploader/__init__.py
new file mode 100644
index 0000000..643d893
--- /dev/null
+++ b/web_image_uploader/__init__.py
@@ -0,0 +1,16 @@
+# -*- coding: utf-8 -*-
+
+# Copyright 2016 Fabien Bourgeois
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
diff --git a/web_image_uploader/__openerp__.py b/web_image_uploader/__openerp__.py
new file mode 100644
index 0000000..8ce79fa
--- /dev/null
+++ b/web_image_uploader/__openerp__.py
@@ -0,0 +1,30 @@
+# -*- coding: utf-8 -*-
+
+# Copyright 2016 Fabien Bourgeois
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
+{
+ 'name': 'Web Image Uploader',
+ 'summary': 'Web Widget : Image Uploader',
+ 'description': 'Web Widget : Image Uploader',
+ 'version': '0.1',
+ 'category': 'Usability',
+ 'author': 'Fabien Bourgeois',
+ 'license': 'AGPL-3',
+ 'application': False,
+ 'installable': True,
+ 'depends': ['web'],
+ 'data': ['views/web_image_uploader.xml']
+}
diff --git a/web_image_uploader/static/src/js/dmuploader.js b/web_image_uploader/static/src/js/dmuploader.js
new file mode 100644
index 0000000..746ddbd
--- /dev/null
+++ b/web_image_uploader/static/src/js/dmuploader.js
@@ -0,0 +1,289 @@
+/*
+ * dmuploader.js - Jquery File Uploader - 0.1
+ * http://www.daniel.com.uy/projects/jquery-file-uploader/
+ *
+ * Copyright (c) 2013 Daniel Morales
+ * Dual licensed under the MIT and GPL licenses.
+ * http://www.daniel.com.uy/doc/license/
+ */
+
+(function($) {
+ var pluginName = 'dmUploader';
+
+ // These are the plugin defaults values
+ var defaults = {
+ url: document.URL,
+ method: 'POST',
+ extraData: {},
+ maxFileSize: 0,
+ maxFiles: 0,
+ allowedTypes: '*',
+ extFilter: null,
+ dataType: null,
+ fileName: 'file',
+ onInit: function(){},
+ onFallbackMode: function(message) {},
+ onNewFile: function(id, file){},
+ onBeforeUpload: function(id){},
+ onComplete: function(){},
+ onUploadProgress: function(id, percent){},
+ onUploadSuccess: function(id, data){},
+ onUploadError: function(id, message){},
+ onFileTypeError: function(file){},
+ onFileSizeError: function(file){},
+ onFileExtError: function(file){},
+ onFilesMaxError: function(file){}
+ };
+
+ var DmUploader = function(element, options)
+ {
+ this.element = $(element);
+
+ this.settings = $.extend({}, defaults, options);
+
+ if(!this.checkBrowser()){
+ return false;
+ }
+
+ this.init();
+
+ return true;
+ };
+
+ DmUploader.prototype.checkBrowser = function()
+ {
+ if(window.FormData === undefined){
+ this.settings.onFallbackMode.call(this.element, 'Browser doesn\'t support Form API');
+
+ return false;
+ }
+
+ if(this.element.find('input[type=file]').length > 0){
+ return true;
+ }
+
+ if (!this.checkEvent('drop', this.element) || !this.checkEvent('dragstart', this.element)){
+ this.settings.onFallbackMode.call(this.element, 'Browser doesn\'t support Ajax Drag and Drop');
+
+ return false;
+ }
+
+ return true;
+ };
+
+ DmUploader.prototype.checkEvent = function(eventName, element)
+ {
+ var element = element || document.createElement('div');
+ var eventName = 'on' + eventName;
+
+ var isSupported = eventName in element;
+
+ if(!isSupported){
+ if(!element.setAttribute){
+ element = document.createElement('div');
+ }
+ if(element.setAttribute && element.removeAttribute){
+ element.setAttribute(eventName, '');
+ isSupported = typeof element[eventName] == 'function';
+
+ if(typeof element[eventName] != 'undefined'){
+ element[eventName] = undefined;
+ }
+ element.removeAttribute(eventName);
+ }
+ }
+
+ element = null;
+ return isSupported;
+ };
+
+ DmUploader.prototype.init = function()
+ {
+ var widget = this;
+
+ widget.queue = new Array();
+ widget.queuePos = -1;
+ widget.queueRunning = false;
+
+ // -- Drag and drop event
+ widget.element.on('drop', function (evt){
+ evt.preventDefault();
+ var files = evt.originalEvent.dataTransfer.files;
+
+ widget.queueFiles(files);
+ });
+
+ //-- Optional File input to make a clickable area
+ widget.element.find('input[type=file]').on('change', function(evt){
+ var files = evt.target.files;
+
+ widget.queueFiles(files);
+
+ $(this).val('');
+ });
+
+ this.settings.onInit.call(this.element);
+ };
+
+ DmUploader.prototype.queueFiles = function(files)
+ {
+ var j = this.queue.length;
+
+ for (var i= 0; i < files.length; i++)
+ {
+ var file = files[i];
+
+ // Check file size
+ if((this.settings.maxFileSize > 0) &&
+ (file.size > this.settings.maxFileSize)){
+
+ this.settings.onFileSizeError.call(this.element, file);
+
+ continue;
+ }
+
+ // Check file type
+ if((this.settings.allowedTypes != '*') &&
+ !file.type.match(this.settings.allowedTypes)){
+
+ this.settings.onFileTypeError.call(this.element, file);
+
+ continue;
+ }
+
+ // Check file extension
+ if(this.settings.extFilter != null){
+ var extList = this.settings.extFilter.toLowerCase().split(';');
+
+ var ext = file.name.toLowerCase().split('.').pop();
+
+ if($.inArray(ext, extList) < 0){
+ this.settings.onFileExtError.call(this.element, file);
+
+ continue;
+ }
+ }
+
+ // Check max files
+ if(this.settings.maxFiles > 0) {
+ if(this.queue.length >= this.settings.maxFiles) {
+ this.settings.onFilesMaxError.call(this.element, file);
+
+ continue;
+ }
+ }
+
+ this.queue.push(file);
+
+ var index = this.queue.length - 1;
+
+ this.settings.onNewFile.call(this.element, index, file);
+ }
+
+ // Only start Queue if we haven't!
+ if(this.queueRunning){
+ return false;
+ }
+
+ // and only if new Failes were successfully added
+ if(this.queue.length == j){
+ return false;
+ }
+
+ this.processQueue();
+
+ return true;
+ };
+
+ DmUploader.prototype.processQueue = function()
+ {
+ var widget = this;
+
+ widget.queuePos++;
+
+ if(widget.queuePos >= widget.queue.length){
+ // Cleanup
+
+ widget.settings.onComplete.call(widget.element);
+
+ // Wait until new files are droped
+ widget.queuePos = (widget.queue.length - 1);
+
+ widget.queueRunning = false;
+
+ return;
+ }
+
+ var file = widget.queue[widget.queuePos];
+
+ // Form Data
+ var fd = new FormData();
+ fd.append(widget.settings.fileName, file);
+
+ // Return from client function (default === undefined)
+ var can_continue = widget.settings.onBeforeUpload.call(widget.element, widget.queuePos);
+
+ // If the client function doesn't return FALSE then continue
+ if( false === can_continue ) {
+ return;
+ }
+
+ // Append extra Form Data
+ $.each(widget.settings.extraData, function(exKey, exVal){
+ fd.append(exKey, exVal);
+ });
+
+ widget.queueRunning = true;
+
+ // Ajax Submit
+ $.ajax({
+ url: widget.settings.url,
+ type: widget.settings.method,
+ dataType: widget.settings.dataType,
+ data: fd,
+ cache: false,
+ contentType: false,
+ processData: false,
+ forceSync: false,
+ xhr: function(){
+ var xhrobj = $.ajaxSettings.xhr();
+ if(xhrobj.upload){
+ xhrobj.upload.addEventListener('progress', function(event) {
+ var percent = 0;
+ var position = event.loaded || event.position;
+ var total = event.total || event.totalSize;
+ if(event.lengthComputable){
+ percent = Math.ceil(position / total * 100);
+ }
+
+ widget.settings.onUploadProgress.call(widget.element, widget.queuePos, percent);
+ }, false);
+ }
+
+ return xhrobj;
+ },
+ success: function (data, message, xhr){
+ widget.settings.onUploadSuccess.call(widget.element, widget.queuePos, data);
+ },
+ error: function (xhr, status, errMsg){
+ widget.settings.onUploadError.call(widget.element, widget.queuePos, errMsg);
+ },
+ complete: function(xhr, textStatus){
+ widget.processQueue();
+ }
+ });
+ }
+
+ $.fn.dmUploader = function(options){
+ return this.each(function(){
+ if(!$.data(this, pluginName)){
+ $.data(this, pluginName, new DmUploader(this, options));
+ }
+ });
+ };
+
+ // -- Disable Document D&D events to prevent opening the file on browser when we drop them
+ $(document).on('dragenter', function (e) { e.stopPropagation(); e.preventDefault(); });
+ $(document).on('dragover', function (e) { e.stopPropagation(); e.preventDefault(); });
+ $(document).on('drop', function (e) { e.stopPropagation(); e.preventDefault(); });
+})(jQuery);
diff --git a/web_image_uploader/web_image_uploader.xml b/web_image_uploader/web_image_uploader.xml
new file mode 100644
index 0000000..b0eea6c
--- /dev/null
+++ b/web_image_uploader/web_image_uploader.xml
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Log
+
+
+
+ Errors
+
+
+
+
+
+
+
diff --git a/web_multi_uploader/__init__.py b/web_multi_uploader/__init__.py
new file mode 100644
index 0000000..9652748
--- /dev/null
+++ b/web_multi_uploader/__init__.py
@@ -0,0 +1,22 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2010 Tiny SPRL ().
+# Author: Naresh Soni
+# Copyright 2015 Cozy Business Solutions Pvt.Ltd
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+##############################################################################
+import controllers
diff --git a/web_multi_uploader/__openerp__.py b/web_multi_uploader/__openerp__.py
new file mode 100644
index 0000000..765b9a8
--- /dev/null
+++ b/web_multi_uploader/__openerp__.py
@@ -0,0 +1,45 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2010 Tiny SPRL ().
+# Author: Naresh Soni
+# Copyright 2015 Cozy Business Solutions Pvt.Ltd
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+##############################################################################
+
+
+{
+ 'name': 'Web Multi Uploader',
+ 'version': '0.1',
+ 'author': 'Cozy Business Solutions Pvt.Ltd.',
+ 'category': 'Tools',
+ 'description': """
+
+This module enables you to upload multiple files as attachments at once
+from top menu and chatter attachment.
+==================================
+
+""",
+ 'version': '1.0',
+ 'depends': ['web'],
+ 'data': [
+ 'views/web_multi_uploader.xml',
+ ],
+ 'qweb': [
+ "static/src/xml/web_multi_uploader.xml",
+ ],
+ 'auto_install': False,
+}
diff --git a/web_multi_uploader/controllers/__init__.py b/web_multi_uploader/controllers/__init__.py
new file mode 100644
index 0000000..f73e5b4
--- /dev/null
+++ b/web_multi_uploader/controllers/__init__.py
@@ -0,0 +1,23 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2010 Tiny SPRL ().
+# Author: Naresh Soni
+# Copyright 2015 Cozy Business Solutions Pvt.Ltd
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+##############################################################################
+
+from . import main
diff --git a/web_multi_uploader/controllers/main.py b/web_multi_uploader/controllers/main.py
new file mode 100644
index 0000000..1e21e98
--- /dev/null
+++ b/web_multi_uploader/controllers/main.py
@@ -0,0 +1,60 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2010 Tiny SPRL ().
+# Author: Naresh Soni
+# Copyright 2015 Cozy Business Solutions Pvt.Ltd
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+##############################################################################
+
+
+
+import base64
+import logging
+import simplejson
+
+import openerp
+from openerp.addons.web import http
+from openerp.http import request
+from openerp.addons.web.controllers.main import serialize_exception, Home
+logger = logging.getLogger(__name__)
+
+
+class Uplodear(Home):
+ @http.route('/web/binary/upload_multi_attachment', type='http', auth="user")
+ @serialize_exception
+ def upload_attachment(self, callback, model, id, ufile):
+ files = http.request.httprequest.files.getlist('ufile')
+ Model = request.session.model('ir.attachment')
+ out = """"""
+ try:
+ args = {}
+ for ufile in files:
+ attachment_id = Model.create({
+ 'name': ufile.filename,
+ 'datas': base64.encodestring(ufile.read()),
+ 'datas_fname': ufile.filename,
+ 'res_model': model,
+ 'res_id': int(id)
+ }, request.context)
+ args[attachment_id] = ufile.filename
+ except Exception:
+ args = {'error': "Something horrible happened"}
+ logger.exception("Fail to upload attachment %s" % ufile.filename)
+ return out % (simplejson.dumps(callback), simplejson.dumps(args))
diff --git a/web_multi_uploader/static/src/js/web_mulit_uploader.js b/web_multi_uploader/static/src/js/web_mulit_uploader.js
new file mode 100644
index 0000000..25f047e
--- /dev/null
+++ b/web_multi_uploader/static/src/js/web_mulit_uploader.js
@@ -0,0 +1,68 @@
+openerp.web_multi_uploader = function(session) {
+ var mail = session.mail;
+ session.mail.ThreadComposeMessage.include({
+ on_attachment_change: function (event) {
+ event.stopPropagation();
+ var self = this;
+ var $target = $(event.target);
+ if ($target.val() !== '') {
+ var filename = $target.val().replace(/.*[\\\/]/,'');
+
+ // if the files exits for this answer, delete the file before upload
+ var attachments=[];
+ for (var i in this.attachment_ids) {
+ if ((this.attachment_ids[i].filename || this.attachment_ids[i].name) == filename) {
+ if (this.attachment_ids[i].upload) {
+ return false;
+ }
+ this.ds_attachment.unlink([this.attachment_ids[i].id]);
+ } else {
+ attachments.push(this.attachment_ids[i]);
+ }
+ }
+ this.attachment_ids = attachments;
+
+ // submit file
+ this.$('form.oe_form_binary_form').submit();
+
+ this.$(".oe_attachment_file").hide();
+
+ var target = $target.get(0);
+ _.each(target.files, function(file){
+ self.attachment_ids.push({
+ 'id': 0,
+ 'name': file.name,
+ 'filename': file.name,
+ 'url': '',
+ 'upload': true
+ });
+ });
+ this.display_attachments();
+ }
+ },
+ on_attachment_loaded: function (event, result) {
+ if (result.erorr) {
+ this.do_warn( session.web.qweb.render('mail.error_upload'), result.error);
+ this.attachment_ids = _.filter(this.attachment_ids, function (val) { return !val.upload; });
+ } else {
+ for (var i in this.attachment_ids) {
+ if (_.contains(_.values(result), this.attachment_ids[i].filename) && this.attachment_ids[i].upload) {
+ var filename = this.attachment_ids[i].filename;
+ var id = _.invert(result)[filename];
+ this.attachment_ids[i]={
+ 'id': id,
+ 'name': filename,
+ 'filename': filename,
+ 'url': mail.ChatterUtils.get_attachment_url(this.session, this.id, id)
+ };
+ }
+ }
+ }
+ this.display_attachments();
+ var $input = this.$('input.oe_form_binary_file');
+ $input.after($input.clone(true)).remove();
+ this.$(".oe_attachment_file").show();
+ },
+
+ });
+};
\ No newline at end of file
diff --git a/web_multi_uploader/static/src/xml/web_multi_uploader.xml b/web_multi_uploader/static/src/xml/web_multi_uploader.xml
new file mode 100644
index 0000000..ad32593
--- /dev/null
+++ b/web_multi_uploader/static/src/xml/web_multi_uploader.xml
@@ -0,0 +1,46 @@
+
+
+