From aa5182bb9e3cd3b59b02aa926fb5f538d6944076 Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Tue, 4 Aug 2015 23:06:01 +0530 Subject: [PATCH] [fix] rename old filenames that start with FileData and fix missing Item images --- erpnext/patches.txt | 1 + .../patches/v5_4/fix_missing_item_images.py | 116 ++++++++++++++++++ 2 files changed, 117 insertions(+) create mode 100644 erpnext/patches/v5_4/fix_missing_item_images.py diff --git a/erpnext/patches.txt b/erpnext/patches.txt index b2d8068eea..e4eefcec21 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -188,3 +188,4 @@ erpnext.patches.v5_4.set_root_and_report_type erpnext.patches.v5_4.notify_system_managers_regarding_wrong_tax_calculation erpnext.patches.v5_4.fix_invoice_outstanding execute:frappe.db.sql("update `tabStock Ledger Entry` set stock_queue = '[]' where voucher_type = 'Stock Reconciliation' and ifnull(qty_after_transaction, 0) = 0") +erpnext.patches.v5_4.fix_missing_item_images diff --git a/erpnext/patches/v5_4/fix_missing_item_images.py b/erpnext/patches/v5_4/fix_missing_item_images.py new file mode 100644 index 0000000000..d782cd179e --- /dev/null +++ b/erpnext/patches/v5_4/fix_missing_item_images.py @@ -0,0 +1,116 @@ +from __future__ import unicode_literals +import frappe +import os +from frappe.utils import get_files_path +from frappe.utils.file_manager import get_content_hash + +def execute(): + files_path = get_files_path() + + # get files that don't have attached_to_name but exist + unlinked_files = get_unlinked_files(files_path) + if not unlinked_files: + return + + fixed_files = fix_files_for_item(files_path, unlinked_files) + + # fix remaining files + for key, file_data in unlinked_files.items(): + if key not in fixed_files: + rename_and_set_content_hash(files_path, unlinked_files, key) + frappe.db.commit() + +def fix_files_for_item(files_path, unlinked_files): + fixed_files = [] + + # make a list of files/something and /files/something to check in child table's image column + file_urls = [key for key in unlinked_files.keys()] + ["/" + key for key in unlinked_files.keys()] + file_item_code = get_file_item_code(file_urls) + + for (file_url, item_code), children in file_item_code.items(): + new_file_url = "/files/{0}".format(unlinked_files[file_url]["file_name"]) + + for row in children: + # print file_url, new_file_url, item_code, row.doctype, row.name + + # replace image in these rows with the new file url + frappe.db.set_value(row.doctype, row.name, "image", new_file_url, update_modified=False) + + # set it as attachment of this item code + file_data = frappe.get_doc("File Data", unlinked_files[file_url]["file"]) + file_data.attached_to_doctype = "Item" + file_data.attached_to_name = item_code + file_data.save() + + # set it as image in Item + if not frappe.db.get_value("Item", item_code, "image"): + frappe.db.set_value("Item", item_code, "image", new_file_url, update_modified=False) + + rename_and_set_content_hash(files_path, unlinked_files, file_url) + + fixed_files.append(file_url) + + # commit + frappe.db.commit() + + return fixed_files + +def rename_and_set_content_hash(files_path, unlinked_files, file_url): + # rename this file + old_filename = os.path.join(files_path, unlinked_files[file_url]["file"]) + new_filename = os.path.join(files_path, unlinked_files[file_url]["file_name"]) + + if not os.path.exists(new_filename): + os.rename(old_filename, new_filename) + + # set content hash if missing + file_data_name = unlinked_files[file_url]["file"] + if not frappe.db.get_value("File Data", file_data_name, "content_hash"): + with open(new_filename, "r") as f: + content_hash = get_content_hash(f.read()) + frappe.db.set_value("File Data", file_data_name, "content_hash", content_hash) + +def get_unlinked_files(files_path): + # find files that have the same name as a File Data doc + # and the file_name mentioned in that File Data doc doesn't exist + # and it isn't already attached to a doc + unlinked_files = {} + files = os.listdir(files_path) + for file in files: + if not frappe.db.exists("File Data", {"file_name": file}): + file_data = frappe.db.get_value("File Data", {"name": file}, + ["file_name", "attached_to_doctype", "attached_to_name"], as_dict=True) + + if (file_data + and file_data.file_name + and file_data.file_name not in files + and not file_data.attached_to_doctype + and not file_data.attached_to_name): + + file_data["file"] = file + unlinked_files["files/{0}".format(file)] = file_data + + return unlinked_files + +def get_file_item_code(file_urls): + # get a map of file_url, item_code and list of documents where file_url will need to be changed in image field + file_item_code = {} + + doctypes = frappe.db.sql_list("""select name from `tabDocType` dt + where istable=1 + and exists (select name from `tabDocField` df where df.parent=dt.name and df.fieldname='item_code') + and exists (select name from `tabDocField` df where df.parent=dt.name and df.fieldname='image')""") + + for doctype in doctypes: + result = frappe.db.sql("""select name, image, item_code, '{0}' as doctype from `tab{0}` + where image in ({1})""".format(doctype, ", ".join(["%s"]*len(file_urls))), + file_urls, as_dict=True) + + for r in result: + key = (r.image, r.item_code) + if key not in file_item_code: + file_item_code[key] = [] + + file_item_code[key].append(r) + + return file_item_code