[Tutorial] Attach Files from items in any document

I’ve created a client script to easily attach files from the selected items.

Basically, it creates a “Get Item Attachments” button to the current document. It lists file extensions and file counts which are attached to the items. You can select file extensions. Then all the files with selected extensions are added to the current document.

Source: This client script will attach files from the items by types to the current document. · GitHub

function GetFileAttachments(frm, arrItemCode) { 
    //Get files which are added to given items
    frappe.db.get_list("File", {
        filters: [
                ['attached_to_name', 'in', arrItemCode],
                ['attached_to_doctype', '=', "Item"]
            ],
    		fields: ["file_name", "file_url", "folder"],
    		limit: 9999
    	}).then((data) => {
    	    let arrFileExt = [];//File extensions
    	    let arrFileExtInfo = [];//json
    	    let strFileExt = "";
    	    let jsonFileInfo = {
    	        file_ext: [],
    	        file_count: []
    	    }
    	    let dIndex = -1;//File index search
    	    for(let i=0; i<data.length; i++) {
    	        strFileExt = data[i].file_name.substring(data[i].file_name.lastIndexOf(".")+1);
    	        if(arrFileExt.indexOf(strFileExt) === -1) {
    	            arrFileExt.push(strFileExt);
    	            arrFileExtInfo.push({'file_ext': strFileExt});
    	            jsonFileInfo.file_ext.push(strFileExt);
    	            jsonFileInfo.file_count.push(1);
    	        } else {
    	            dIndex = jsonFileInfo.file_ext.indexOf(strFileExt);
    	            jsonFileInfo.file_count[dIndex] = jsonFileInfo.file_count[dIndex] + 1;
    	        }
    	    }
    	    for(let i=0; i<arrFileExtInfo.length; i++) {
    	        strFileExt = arrFileExtInfo[i].file_ext;
    	        dIndex = jsonFileInfo.file_ext.indexOf(strFileExt);
    	        arrFileExtInfo[i].file_count = jsonFileInfo.file_count[dIndex];
    	    }
    	    
            const fields = [
            {
                label: 'Files',
                fieldtype: 'Table',
                fieldname: 'files',
                description: __('Select File Types'),
                fields: [
                {
                    fieldtype: 'Data',
                    fieldname: 'file_ext',
                    options: '',
                    reqd: 0,
                    readonly: 1,
                    label: __('File Type'),
                    in_list_view: 1
                },
                {
                    fieldtype: 'Int',
                    fieldname: 'file_count',
                    options: '',
                    reqd: 0,
                    readonly: 1,
                    label: __('File Count'),
                    in_list_view: 1
                }
            	],
                data: arrFileExtInfo,
                get_data: () => {
                    return r.message//ERR
                }
            }]
            var d = new frappe.ui.Dialog({
                title: __('Select File Types'),
                fields: fields,
                primary_action: function(dataTable) {
                    let arrPromFile = [];
                    for(let i=0; i<d.fields_dict.files.df.data.length; i++) {//Her dosya turu icin
                        strFileExt = d.fields_dict.files.df.data[i].file_ext;
                        //Does the file type is selected?
                        if (typeof d.fields_dict.files.df.data[i].__checked !== 'undefined') {
                            if (d.fields_dict.files.df.data[i].__checked === 1) {
                                //Select the files which have the same extension
                                for(let j=0; j<data.length; j++) {//For each file
                                    if (strFileExt == data[j].file_name.substring(data[j].file_name.lastIndexOf(".")+1)) {
                                        //Extensions match
                                        const docFile = frappe.model.get_new_doc('File');
                                        docFile.file_name = data[j].file_name;
                                        docFile.attached_to_doctype = frm.doctype;
                                        docFile.attached_to_name = frm.docname;
                                        docFile.file_url = data[j].file_url;
                                        docFile.folder = data[j].folder;
                                        arrPromFile.push(frappe.db.insert(docFile));
                                    }
                                }
                            }
                        }
                    }//File operations are completed.
                    d.hide();
                    Promise.all(arrPromFile).then((result) => {
                        frm.reload_doc();
                    })
            	},
            	primary_action_label: __('Attach Files')
            });
            d.show();
	    });
}

frappe.ui.form.on('Request for Quotation', {
	refresh(frm) {
	    frm.add_custom_button(__('Get Item Attachments'), function(){
                let arrItemCode = [];
            
                $.each(frm.doc.items,  function(i,  d) {
                    arrItemCode.push(d.item_code);
                });
                GetFileAttachments(frm, arrItemCode);
            });
	}
});

PS: To make it work on document types other than the “Request for Quotation” you need to change line 105 to needed document type. Like “Purchase Order”.

16 Likes

Good one!

Quite amazing to see what can be done without opening the trunk !

Thanks for sharing,

1 Like

Very good contribution, very useful!

I see make a copy of the file, is a way tu use the same file of the item and not copy the file, like just make new file doc using an existing file?

image

Hi there. I didn’t understand the question here.