I'm trying to make a feature in Odoo that allows a user to upload multiple files from an attachment form, and when he submits it, it creates as many attachments as selected documents.
I created a widget for the 'binary' field that allows the multi selection (Adding 'multiple' argument to 'input' tag in a Qweb template), but at this point i'm struggling with attachments creation and linking them with the concerned field from JS.
my widget :
odoo.define('lettermgmt', function(require)
{
'use strict';
var core = require('web.core');
var FieldBinaryFile = core.form_widget_registry.get('binary');
var FieldBinaryMultipleFiles = FieldBinaryFile.extend({
template : 'FieldBinaryMultipleFiles',
});
core.form_widget_registry.add('binary_multiple_files',FieldBinaryMultipleFiles);
});
My first guess was to override on_file_change
method, loop over "e.target.files
" and make a POST request for each file on '/web/binary/upload_attachment
'. this creates the attachments but i couldn't figure out how to link them to my model (relational field).
I'll appreciate any help :)
I finally found a solution :
The idea is to create a custom char widget with specific behavior. JS Code here :
odoo.define('cutom_module', function(require)
{
'use strict';
var core = require('web.core');
var Char = core.form_widget_registry.get('char');
var import_button = Char.extend({
template : "import_button",
events : {
'change' : 'import_files',
},
init : function(){
this._super.apply(this,arguments);
this._start = null;
},
start : function() {
},
import_files : function(event){
var self = this;
var files = event.target.files; // Get Selected files
var attachment_ids = self.getParent().fields[ 'attachment_ids' ]; // Get existing attachments
var data64 = null;
var values_list = [];
_.each(files, function(file){
// Check if the file is already in the attachments, must specify field name here :/
if(self.already_attached(attachment_ids.get_value(),file.name)){
return;
}
var filereader = new FileReader();
filereader.readAsDataURL(file);
filereader.onloadend = function(upload) {
var data = upload.target.result;
data64 = data.split(',')[1];
var values = {
'name' : file.name,
'type' : 'binary',
'datas' : data64,
};
values_list.push([ 0, 0, values]);
if(values_list.length == files.length){
attachment_ids.set_value(values_list);
}
};
});
},
already_attached : function (attachments,filename) {
for(var i=0;i<attachments.length;i++){
if(attachments[i][2]['name'] == filename){
return true;
}
}
return false;
},
});
core.form_widget_registry.add('import_button',import_button);
});
Qweb for import_button template :
<?xml version="1.0" encoding="UTF-8"?>
<templates xml:space="preserve">
<t t-name="HiddenInputMultipleFiles">
<div t-attf-class="oe_hidden_input_file #{fileupload_class or ''}" t-att-style="fileupload_style">
<form class="o_form_binary_form" t-att-target="fileupload_id"
method="post" enctype="multipart/form-data" t-att-action="'/web/binary/upload_attachment'">
<input type="hidden" name="csrf_token" t-att-value="csrf_token"/>
<input type="hidden" name="session_id" value="" t-if="widget.session.override_session"/>
<input type="hidden" name="callback" t-att-value="fileupload_id"/>
<t t-raw="0"/>
<input type="file" class="o_form_input_file" name="ufile" t-if="widget.widget!='image'" multiple="multiple"/>
<input type="file" class="o_form_input_file" name="ufile" accept="image/*" t-if="widget.widget=='image'"/>
</form>
<iframe t-att-id="fileupload_id" t-att-name="fileupload_id" style="display: none"/>
</div>
</t>
<div t-name="import_button" t-attf-class="base #{cls}" class="oe_web_example">
<p>
<t t-call="HiddenInputMultipleFiles">
</t>
</p>
</div>
</templates>
View :
....
<field name="import_files" widget="import_button"/>
<field name="attachment_ids" widget="one2many_list"
>
<tree create="0">
<field name="name" string="File name"/>
</tree>
</field>
....
and the model :
....
attachment_ids = fields.Many2many(comodel_name="ir.attachment",string="Documents")
import_files = fields.Char(string=" ")
....
If you have questions or suggestions for improvements let me know :)