def save_and_attach(content, to_doctype, to_name, folder, hashname=None, is_private=1): """ Save content to disk and create a File document. File document is linked to another document. """ if not hashname: file_name = "{0}.pdf".format( to_name.replace(" ", "-").replace("/", "-")) else: # use a hased file name file_name = "{0}.pdf".format( hashlib.md5("{0}{1}".format( to_name, time.time()).encode('utf-8')).hexdigest()) save_file(file_name, content, to_doctype, to_name, folder=folder, is_private=is_private) return
def create_communications_for_sync(erpnext_support_issue, subject, description, raised_by, recipients, attachments=None): comm = frappe.get_doc({ "doctype": "Communication", "subject": subject, "content": description, "recipients": recipients, "sent_or_received": "Received", "reference_doctype": "ERPNext Support Issue", "communication_medium": "Email", "sender": raised_by, "reference_name": erpnext_support_issue, "has_attachment": 1 if attachments else 0 }).insert(ignore_permissions=True) if attachments: attachments = json.loads(attachments) for d in attachments: save_file(d.get("filename"), base64.b64decode(d.get("content")), "Communication", comm.name)
def create_reply_from_customer(erpnext_support_user, subject, description, raised_by, recipients, bench_site, frappe_issue_id, attachments=None): authenticate_erpnext_support_user(erpnext_support_user) comm = frappe.get_doc({ "doctype": "Communication", "subject": subject, "content": description, "sent_or_received": "Received", "reference_doctype": "Issue", "communication_medium": "Email", "sender": raised_by, "recipients": recipients, "reference_name": frappe_issue_id, "has_attachment": 1 if attachments else 0 }).insert(ignore_permissions=True) if attachments: attachments = json.loads(attachments) for d in attachments: save_file(d.get("filename"), base64.b64decode(d.get("content")), "Communication", comm.name) frappe.db.set_value("Issue", frappe_issue_id, "status", "Open") return json.dumps({"last_sync_on": get_datetime_str(now_datetime())})
def payment_success(self): self.switch_to_frame('main_part') save_file(self.docname + ' Online Payment Screenshot.png', self.br.get_screenshot_as_png(), self.doctype, self.docname, is_private=1) ref_no = '-' if self.data.transfer_type == 'Transfer within the bank': ref_no = self.br.execute_script( "return $('table.transTable td:nth-child(3) > span').text();" ) or '-' elif self.data.transfer_type == 'Transfer to other bank (NEFT)': ref_no = (self.get_element( "//td[contains(text(),'Reference Number')]/following-sibling::td[last()]", 'xpath').text or '-').strip() frappe.publish_realtime('payment_success', { 'ref_no': ref_no, 'uid': self.uid }, user=frappe.session.user, doctype="Payment Entry", docname=self.docname) frappe.db.commit() self.logout()
def payment_success(self): self.switch_to_frame("main_part") save_file( self.docname + " Online Payment Screenshot.png", self.br.get_screenshot_as_png(), self.doctype, self.docname, is_private=1, ) ref_no = "-" if self.data.transfer_type == "Transfer within the bank": ref_no = (self.br.execute_script( "return $('table.transTable td:nth-child(3) > span').text();") or "-") elif self.data.transfer_type == "Transfer to other bank (NEFT)": ref_no = (self.get_element( "//td[contains(text(),'Reference Number')]/following-sibling::td[last()]", "xpath", ).text or "-").strip() frappe.publish_realtime( "payment_success", { "ref_no": ref_no, "uid": self.uid }, user=frappe.session.user, doctype="Payment Entry", docname=self.docname, ) frappe.db.commit() self.logout()
def import_fints_transactions(self, fints_import): """Create payment entries by FinTS transactions. :param fints_import: fints_import doc name :type fints_import: str :return: List of max 10 transcations and all new payment entries """ try: self.interactive.show_progress_realtime( _("Start transcation import"), 40, reload=False) curr_doc = frappe.get_doc("FinTS Import", fints_import) new_payments = None tansactions = self.get_fints_transactions(curr_doc.from_date, curr_doc.to_date) try: save_file(fints_import + ".json", json.dumps(tansactions, ensure_ascii=False).replace( ",", ",\n").encode('utf8'), 'FinTS Import', fints_import, folder='Home/Attachments/FinTS', decode=False, is_private=1, df=None) except Exception as e: frappe.throw(_("Failed to attach file"), e) if (len(tansactions) == 0): frappe.msgprint(_("No transcations found")) else: if (len(tansactions) == 1): curr_doc.start_date = tansactions[0]["date"] curr_doc.end_date = tansactions[0]["date"] else: curr_doc.start_date = tansactions[0]["date"] curr_doc.end_date = tansactions[-1]["date"] importer = ImportPaymentEntry(self.fints_login, self.interactive) importer.fints_import(tansactions) if len(importer.payment_entries) == 0: frappe.msgprint(_("No new payments found")) else: # Save payment entries frappe.db.commit() frappe.msgprint( _("Found a total of '{0}' payments").format( len(importer.payment_entries))) new_payments = importer.payment_entries curr_doc.submit() self.interactive.show_progress_realtime( _("Payment entry import completed"), 100, reload=False) return {"transactions": tansactions[:10], "payments": new_payments} except Exception as e: frappe.throw( _("Error parsing transactions<br>{0}").format(str(e)), frappe.get_traceback())
def setUp(self): self.attached_to_doctype, self.attached_to_docname = make_test_doc() self.test_content1 = test_content1 self.test_content2 = test_content2 self.saved_file1 = save_file('hello.txt', self.test_content1, self.attached_to_doctype, self.attached_to_docname) self.saved_file2 = save_file('hello.txt', self.test_content2, self.attached_to_doctype, self.attached_to_docname) self.saved_filename1 = get_files_path(self.saved_file1.file_name) self.saved_filename2 = get_files_path(self.saved_file2.file_name)
def prepare_and_attach_invoice(doc): progressive_name, progressive_number = get_progressive_name_and_number(doc) invoice = prepare_invoice(doc, progressive_number) invoice_xml = frappe.render_template('erpnext/regional/italy/e-invoice.xml', context={"doc": invoice}, is_path=True) xml_filename = progressive_name + ".xml" save_file(xml_filename, invoice_xml, dt=doc.doctype, dn=doc.name, is_private=True)
def zip_attachments(document): zip_count = 1 zip_size = 0 document = json.loads(document) document2 = frappe._dict(document) fname = get_file_name(document2.name + " (zip 1).zip", random_string(7)) import zipfile docZip = zipfile.ZipFile(fname, "w", zipfile.ZIP_DEFLATED) for file_url in frappe.db.sql( """select file_url, is_private from `tabFile` where attached_to_doctype = %(doctype)s and attached_to_name = %(docname)s""", { 'doctype': document2.doctype, 'docname': document2.name }, as_dict=True): frappe.msgprint("Adding " + file_url.file_url) if file_url.file_url.startswith("/private/files/"): path = get_files_path(*file_url.file_url.split( "/private/files/", 1)[1].split("/"), is_private=1) elif file_url.file_url.startswith("/files/"): path = get_files_path( *file_url.file_url.split("/files/", 1)[1].split("/")) path = encode(path) if zip_size + os.path.getsize(path) > 10000000: zip_count = zip_count + 1 zip_size = 0 docZip.close() with open(encode(fname), 'r') as f: content = f.read() content = base64.b64encode(content) save_file(fname, content, document2.doctype, document2.name, "Home/Attachments", 1) fname = get_file_name( document2.name + " (zip " + str(zip_count) + ").zip", random_string(7)) docZip = zipfile.ZipFile(fname, "w", zipfile.ZIP_DEFLATED) docZip.write(path, os.path.basename(path)) zip_size = zip_size + docZip.getinfo( os.path.basename(path)).compress_size docZip.close() with open(encode(fname), 'r') as f: content = f.read() content = base64.b64encode(content) save_file(fname, content, document2.doctype, document2.name, "Home/Attachments", 1)
def prepare_and_attach_invoice(doc): progressive_name, progressive_number = get_progressive_name_and_number(doc) invoice = prepare_invoice(doc, progressive_number) invoice_xml = frappe.render_template('erpnext/regional/italy/e-invoice.xml', context={"doc": invoice}, is_path=True) invoice_xml = invoice_xml.replace("&", "&") xml_filename = progressive_name + ".xml" save_file(xml_filename, invoice_xml, dt=doc.doctype, dn=doc.name, is_private=True)
def setUp(self): self.attached_to_doctype1, self.attached_to_docname1 = make_test_doc() self.attached_to_doctype2, self.attached_to_docname2 = make_test_doc() self.test_content1 = test_content1 self.test_content2 = test_content1 self.orig_filename = 'hello.txt' self.dup_filename = 'hello2.txt' self.saved_file1 = save_file(self.orig_filename, self.test_content1, self.attached_to_doctype1, self.attached_to_docname1) self.saved_file2 = save_file(self.dup_filename, self.test_content2, self.attached_to_doctype2, self.attached_to_docname2) self.saved_filename1 = get_files_path(self.saved_file1.file_name) self.saved_filename2 = get_files_path(self.saved_file2.file_name)
def create_pdf(doctype, docname, printformat): # create html html = frappe.get_print(doctype, docname, print_format=printformat) # create pdf pdf = frappe.utils.pdf.get_pdf(html) # save and attach pdf now = datetime.now() ts = "{0:04d}-{1:02d}-{2:02d}".format(now.year, now.month, now.day) file_name = "{0}_{1}.pdf".format( ts, docname.replace(" ", "_").replace("/", "_")) save_file(file_name, pdf, doctype, docname, is_private=1) return
def save_and_attach(content, to_doctype, to_name, folder): """ Save content to disk and create a File document. File document is linked to another document. """ file_name = "{}.pdf".format(to_name.replace(" ", "-").replace("/", "-")) save_file(file_name, content, to_doctype, to_name, folder=folder, is_private=1) return
def throw(self, message, screenshot=False): js = "frappe.hide_msgprint();" if screenshot: save_file('payment_error_{}.png'.format(self.uid), self.br.get_screenshot_as_png(), self.doctype, self.docname, is_private=1) frappe.db.commit() js += " if (cur_frm) cur_frm.reload_doc();" message += " (See attached screenshot)" frappe.emit_js(js) self.logout() frappe.throw(message)
def save_attachments_in_doc(self, doc): """Save email attachments in given document.""" from frappe.utils.file_manager import save_file, MaxFileSizeReachedError for attachment in self.attachments: try: save_file(attachment['fname'], attachment['fcontent'], doc.doctype, doc.name) except MaxFileSizeReachedError: # WARNING: bypass max file size exception pass except frappe.DuplicateEntryError: # same file attached twice?? pass
def save_attachments_in_doc(self, doc): """Save email attachments in given document.""" from frappe.utils.file_manager import save_file, MaxFileSizeReachedError for attachment in self.attachments: try: save_file(attachment['filename'], attachment['content'], doc.doctype, doc.name) except MaxFileSizeReachedError: # WARNING: bypass max file size exception pass except frappe.DuplicateEntryError: # same file attached twice?? pass
def create_flyer_pdf(name): block = frappe.get_doc("Block", name) # create html html = frappe.get_print("Block", name, print_format=block.flyer_print_format) # create pdf pdf = frappe.utils.pdf.get_pdf(html) # clear attached files remove_all("Block", name) # save and attach pdf file_name = "{0}.pdf".format(name.replace(" ", "_").replace("/", "_")) save_file(file_name, pdf, "Block", name, is_private=0) return
def build_long_fiscal_year_print(fiscal_year): fiscal_year = frappe.get_doc("Fiscal Year", fiscal_year) # clear attached files remove_all("Fiscal Year", fiscal_year.name) for c in fiscal_year.companies: # create html if not c.print_format: frappe.log_error( _("Please specify a print format for company {0}", _("Print Fiscal Year") ) ) html = frappe.get_print("Fiscal Year", fiscal_year.name, print_format=c.print_format) # create pdf pdf = frappe.utils.pdf.get_pdf(html) # save and attach pdf file_name = ("{0}_{1}.pdf".format(fiscal_year.name, c.company)).replace(" ", "_").replace("/", "_") save_file(file_name, pdf, "Fiscal Year", fiscal_year.name, is_private=1) return
def payment_success_action(self): # Get reference no. and screenshot << refno is the id save_file(self.docname + ' Online Payment Screenshot.png', self.br.get_screenshot_as_png(), 'Payment Entry', self.docname) if self.transfer_type == 'Transfer within the bank': ref_no = self.br.find_element_by_id('refno').text else: ref_no = self.br.find_element_by_class_name('clsreferenceno').text frappe.publish_realtime('payment_success', {'ref_no': ref_no}, user=frappe.session.user) self.logout()
def create_json_gz_file(data, dt, dn): # Storing data in CSV file causes information loss # Reports like P&L Statement were completely unsuable because of this json_filename = '{0}.json.gz'.format(frappe.utils.data.format_datetime(frappe.utils.now(), "Y-m-d-H:M")) encoded_content = frappe.safe_encode(frappe.as_json(data)) # GZip compression seems to reduce storage requirements by 80-90% compressed_content = gzip_compress(encoded_content) save_file( fname=json_filename, content=compressed_content, dt=dt, dn=dn, folder=None, is_private=False)
def create_json_gz_file(data, dt, dn): # Storing data in CSV file causes information loss # Reports like P&L Statement were completely unsuable because of this json_filename = '{0}.json.gz'.format(frappe.utils.data.format_datetime(frappe.utils.now(), "Y-m-d-H:M")) encoded_content = frappe.safe_encode(frappe.as_json(data)) # GZip compression seems to reduce storage requirements by 80-90% compressed_content = gzip_compress(encoded_content) save_file( fname=json_filename, content=compressed_content, dt=dt, dn=dn, folder=None, is_private=True)
def attach_file(filename=None, filedata=None, doctype=None, docname=None, folder=None, decode_base64=False, is_private=None, docfield=None): '''Attach a file to Document (POST) :param filename: filename e.g. test-file.txt :param filedata: base64 encode filedata which must be urlencoded :param doctype: Reference DocType to attach file to :param docname: Reference DocName to attach file to :param folder: Folder to add File into :param decode_base64: decode filedata from base64 encode, default is False :param is_private: Attach file as private file (1 or 0) :param docfield: file to attach to (optional)''' request_method = frappe.local.request.environ.get("REQUEST_METHOD") if request_method.upper() != "POST": frappe.throw(_("Invalid Request")) doc = frappe.get_doc(doctype, docname) if not doc.has_permission(): frappe.throw(_("Not permitted"), frappe.PermissionError) f = save_file(filename, filedata, doctype, docname, folder, decode_base64, is_private, docfield) if docfield and doctype: doc.set(docfield, f.file_url) doc.save() return f.as_dict()
def create_items(args): for i in xrange(1, 6): item = args.get("item_" + str(i)) if item: item_group = _(args.get("item_group_" + str(i))) is_sales_item = args.get("is_sales_item_" + str(i)) is_purchase_item = args.get("is_purchase_item_" + str(i)) is_stock_item = item_group != _("Services") default_warehouse = "" if is_stock_item: default_warehouse = frappe.db.get_value( "Warehouse", filters={ "warehouse_name": _("Finished Goods") if is_sales_item else _("Stores"), "company": args.get("company_name") }) try: frappe.get_doc({ "doctype": "Item", "item_code": item, "item_name": item, "description": item, "show_in_website": 1, "is_sales_item": is_sales_item, "is_purchase_item": is_purchase_item, "is_stock_item": is_stock_item and 1 or 0, "item_group": item_group, "stock_uom": _(args.get("item_uom_" + str(i))), "default_warehouse": default_warehouse }).insert() if args.get("item_img_" + str(i)): item_image = args.get("item_img_" + str(i)).split(",") if len(item_image) == 3: filename, filetype, content = item_image fileurl = save_file(filename, content, "Item", item, decode=True).file_url frappe.db.set_value("Item", item, "image", fileurl) if args.get("item_price_" + str(i)): item_price = flt(args.get("item_price_" + str(i))) if is_sales_item: price_list_name = frappe.db.get_value( "Price List", {"selling": 1}) make_item_price(item, price_list_name, item_price) if is_purchase_item: price_list_name = frappe.db.get_value( "Price List", {"buying": 1}) make_item_price(item, price_list_name, item_price) except frappe.NameError: pass
def create_items(args): for i in xrange(1,6): item = args.get("item_" + str(i)) if item: item_group = args.get("item_group_" + str(i)) is_sales_item = args.get("is_sales_item_" + str(i)) is_purchase_item = args.get("is_purchase_item_" + str(i)) is_stock_item = item_group!=_("Services") default_warehouse = "" if is_stock_item: if is_sales_item: default_warehouse = _("Finished Goods") + " - " + args.get("company_abbr") else: default_warehouse = _("Stores") + " - " + args.get("company_abbr") frappe.get_doc({ "doctype":"Item", "item_code": item, "item_name": item, "description": item, "is_sales_item": "Yes" if is_sales_item else "No", "is_purchase_item": "Yes" if is_purchase_item else "No", "show_in_website": 1, "is_stock_item": is_stock_item and "Yes" or "No", "item_group": item_group, "stock_uom": args.get("item_uom_" + str(i)), "default_warehouse": default_warehouse }).insert() if args.get("item_img_" + str(i)): item_image = args.get("item_img_" + str(i)).split(",") if len(item_image)==3: filename, filetype, content = item_image fileurl = save_file(filename, content, "Item", item, decode=True).file_url frappe.db.set_value("Item", item, "image", fileurl)
def prepare_data_for_import(self, file_content, file_name, encoded_content): for line in file_content.find_all("DatiGeneraliDocumento"): invoices_args = { "company": self.company, "naming_series": self.invoice_series, "document_type": line.TipoDocumento.text, "bill_date": get_datetime_str(line.Data.text), "bill_no": line.Numero.text, "total_discount": 0, "items": [], "buying_price_list": self.default_buying_price_list } if not invoices_args.get("bill_no", ''): frappe.throw(_("Numero has not set in the XML file")) supp_dict = get_supplier_details(file_content) invoices_args["destination_code"] = get_destination_code_from_file(file_content) self.prepare_items_for_invoice(file_content, invoices_args) invoices_args["taxes"] = get_taxes_from_file(file_content, self.tax_account) invoices_args["terms"] = get_payment_terms_from_file(file_content) supplier_name = create_supplier(self.supplier_group, supp_dict) address = create_address(supplier_name, supp_dict) pi_name = create_purchase_invoice(supplier_name, file_name, invoices_args, self.name) self.file_count += 1 if pi_name: self.purchase_invoices_count += 1 file_save = save_file(file_name, encoded_content, "Purchase Invoice", pi_name, folder=None, decode=False, is_private=0, df=None)
def setUp(self): self.attached_to_doctype, self.attached_to_docname = make_test_doc() self.test_content = test_content1 self.saved_file = save_file('hello.txt', self.test_content, self.attached_to_doctype, self.attached_to_docname) self.saved_filename = get_files_path(self.saved_file.file_name)
def create_logo(args): if args.get("attach_logo"): filename, filetype, content = args.get("attach_logo").split(",") fileurl = save_file(filename, content, "Website Settings", "Website Settings", decode=True).file_url frappe.db.set_value("Website Settings", "Website Settings", "banner_html", "<img src='%s' style='max-width: 100%%;'>" % fileurl)
def attach_file(doctype, docname, filedata): if not filedata: return fd_json = json.loads(filedata) fd_list = list(fd_json["files_data"]) for fd in fd_list: attach_type = frappe.get_value("Tipo de Adjunto", fd["attach_type"], ["allow_more_than_one", "max_attacthments"], as_dict=True) file_list = frappe.get_list("File", { "file_name": ["like", "{}%".format(fd["filename"].split(".pdf")[0])]}) if file_list: if (not attach_type.allow_more_than_one and len(file_list))\ or\ (attach_type.allow_more_than_one and attach_type.max_attacthments and flt(attach_type.max_attacthments) <= len(file_list)): frappe.throw("No puede agregar mas adjuntos de este tipo") fd["filename"] = fd["filename"].replace(".pdf", "-{}.pdf".format(len(file_list))) fd["filename"] = s_sanitize(fd["filename"], upper=False) filedoc = save_file(fd["filename"], fd["dataurl"], doctype, docname, decode=True, is_private=True)
def update_user_name(args): if args.get("email"): args['name'] = args.get("email") _mute_emails, frappe.flags.mute_emails = frappe.flags.mute_emails, True doc = frappe.get_doc({ "doctype":"User", "email": args.get("email"), "first_name": args.get("first_name"), "last_name": args.get("last_name") }) doc.flags.no_welcome_mail = True doc.insert() frappe.flags.mute_emails = _mute_emails from frappe.auth import _update_password _update_password(args.get("email"), args.get("password")) else: args['name'] = frappe.session.user # Update User if not args.get('last_name') or args.get('last_name')=='None': args['last_name'] = None frappe.db.sql("""update `tabUser` SET first_name=%(first_name)s, last_name=%(last_name)s WHERE name=%(name)s""", args) if args.get("attach_user"): attach_user = args.get("attach_user").split(",") if len(attach_user)==3: filename, filetype, content = attach_user fileurl = save_file(filename, content, "User", args.get("name"), decode=True).file_url frappe.db.set_value("User", args.get("name"), "user_image", fileurl) add_all_roles_to(args.get("name"))
def create_items(args): for i in xrange(1,6): item = args.get("item_" + str(i)) if item: item_group = args.get("item_group_" + str(i)) is_sales_item = args.get("is_sales_item_" + str(i)) is_purchase_item = args.get("is_purchase_item_" + str(i)) is_stock_item = item_group!=_("Services") default_warehouse = "" if is_stock_item: default_warehouse = frappe.db.get_value("Warehouse", filters={ "warehouse_name": _("Finished Goods") if is_sales_item else _("Stores"), "company": args.get("company_name").strip() }) frappe.get_doc({ "doctype":"Item", "item_code": item, "item_name": item, "description": item, "is_sales_item": "Yes" if is_sales_item else "No", "is_purchase_item": "Yes" if is_purchase_item else "No", "show_in_website": 1, "is_stock_item": is_stock_item and "Yes" or "No", "item_group": item_group, "stock_uom": args.get("item_uom_" + str(i)), "default_warehouse": default_warehouse }).insert() if args.get("item_img_" + str(i)): item_image = args.get("item_img_" + str(i)).split(",") if len(item_image)==3: filename, filetype, content = item_image fileurl = save_file(filename, content, "Item", item, decode=True).file_url frappe.db.set_value("Item", item, "image", fileurl)
def update_profile_name(args): if args.get("email"): args['name'] = args.get("email") frappe.flags.mute_emails = True frappe.bean({ "doctype": "Profile", "email": args.get("email"), "first_name": args.get("first_name"), "last_name": args.get("last_name") }).insert() frappe.flags.mute_emails = False from frappe.auth import _update_password _update_password(args.get("email"), args.get("password")) else: args['name'] = frappe.session.user # Update Profile if not args.get('last_name') or args.get('last_name') == 'None': args['last_name'] = None frappe.db.sql( """update `tabProfile` SET first_name=%(first_name)s, last_name=%(last_name)s WHERE name=%(name)s""", args) if args.get("attach_profile"): filename, filetype, content = args.get("attach_profile").split(",") fileurl = save_file(filename, content, "Profile", args.get("name"), decode=True).file_name frappe.db.set_value("Profile", args.get("name"), "user_image", fileurl) add_all_roles_to(args.get("name"))
def attach_all_boms(document): """This function attaches drawings to the purchase order based on the items being ordered""" document = json.loads(document) document2 = frappe._dict(document) current_attachments = [] for file_url in frappe.db.sql("""select file_name from `tabFile` where attached_to_doctype = %(doctype)s and attached_to_name = %(docname)s""", {'doctype': document2.doctype, 'docname': document2.name}, as_dict=True ): current_attachments.append(file_url.file_name) # add the directly linked drawings boms = [] for item in document["items"]: #add the boms boms = get_bom_pdf(boms, item["item_code"]) count = 0 for bom_doc in boms: #frappe.msgprint(item_doc) bom = frappe.get_doc("BOM",bom_doc) # Check to see if this file is attached to the one we are looking for if not (bom.name + ".pdf") in current_attachments: count = count + 1 my_attach = frappe.attach_print(bom.doctype, bom.name, doc=bom) myFile = save_file(my_attach['fname'], my_attach['fcontent'], document2.doctype, document2.name, "Home/Attachments", decode=False, is_private=1) myFile.file_name = my_attach['fname'] myFile.save() current_attachments.append(my_attach['fname']) frappe.msgprint("Attached {0} boms".format(count))
def file_upload(data): dts=json.loads(data) #print dts #frappe.errprint(dts) qry="select user from __Auth where user='******'username'])+"' and password=password('"+cstr(dts['userpass'])+"') " valid=frappe.db.sql(qry) if not valid: return { "status":"401", "message":"User name or Password is incorrect" } from frappe.utils.file_manager import save_file filedata=save_file(fname=dts['filename'],content=base64.b64decode(dts['fdata']),dt=dts['tbl'],dn=dts['name']) comment = frappe.get_doc(dts['tbl'], dts['name']).add_comment("Attachment", _("Added {0}").format("<a href='{file_url}' target='_blank'>{file_name}</a>".format(**filedata.as_dict()))) if dts['tbl']=='Member': frappe.db.sql("update tabMember set image=%s where name=%s",(filedata.file_url,dts['name'])) #frappe.errprint(filedata.name,filedata.file_name,filedata.file_url,comment.as_dict()) return { "name": filedata.name, "file_name": filedata.file_name, "file_url": filedata.file_url, "comment": comment.as_dict() }
def save_attachments_in_doc(self, doc): """Save email attachments in given document.""" from frappe.utils.file_manager import save_file, MaxFileSizeReachedError saved_attachments = [] for attachment in self.attachments: try: file_data = save_file(attachment['fname'], attachment['fcontent'], doc.doctype, doc.name, is_private=1) saved_attachments.append(file_data) if attachment['fname'] in self.cid_map: self.cid_map[file_data.name] = self.cid_map[ attachment['fname']] except MaxFileSizeReachedError: # WARNING: bypass max file size exception pass except frappe.DuplicateEntryError: # same file attached twice?? pass return saved_attachments
def zip_attachments(document): zip_count = 1 zip_size = 0 document = json.loads(document) document2 = frappe._dict(document) fname = get_file_name(document2.name + " (zip 1).zip", random_string(7)) import zipfile docZip = zipfile.ZipFile(fname,"w", zipfile.ZIP_DEFLATED) for file_url in frappe.db.sql("""select file_url, is_private from `tabFile` where attached_to_doctype = %(doctype)s and attached_to_name = %(docname)s""", {'doctype': document2.doctype, 'docname': document2.name}, as_dict=True ): frappe.msgprint("Adding " + file_url.file_url) if file_url.file_url.startswith("/private/files/"): path = get_files_path(*file_url.file_url.split("/private/files/", 1)[1].split("/"), is_private=1) elif file_url.file_url.startswith("/files/"): path = get_files_path(*file_url.file_url.split("/files/", 1)[1].split("/")) path = encode(path) if zip_size + os.path.getsize(path) > 10000000: zip_count = zip_count + 1 zip_size = 0 docZip.close() with open(encode(fname), 'r') as f: content = f.read() content = base64.b64encode(content) save_file(fname, content, document2.doctype, document2.name, "Home/Attachments", 1) fname = get_file_name(document2.name + " (zip " + str(zip_count) + ").zip", random_string(7)) docZip = zipfile.ZipFile(fname,"w", zipfile.ZIP_DEFLATED) docZip.write(path, os.path.basename(path)) zip_size = zip_size + docZip.getinfo(os.path.basename(path)).compress_size docZip.close() with open(encode(fname), 'r') as f: content = f.read() content = base64.b64encode(content) save_file(fname, content, document2.doctype, document2.name, "Home/Attachments", 1)
def download_test(self): str_save_file = "A" str_save_file += frappe.db.get_value("Electronic Funds Transfer Bank Detail", self.bank_account, "originator_id").zfill(10) str_save_file += self.file_creation_number.zfill(4) today = datetime.date.today() str_save_file += "0" + today.strftime("%y%j") str_save_file += frappe.db.get_value("Electronic Funds Transfer Bank Detail", self.bank_account, "destination_data_centre_code").zfill(5) str_save_file += "\nXC430" str_save_file += "0" + today.strftime("%y%j") str_save_file += frappe.db.get_value("Electronic Funds Transfer Bank Detail", self.bank_account, "originators_short").ljust(15) str_save_file += frappe.db.get_value("Electronic Funds Transfer Bank Detail", self.bank_account, "originators_long").ljust(30) str_save_file += "0" str_save_file += frappe.db.get_value("Electronic Funds Transfer Bank Detail", self.bank_account, "institution_number").ljust(3) str_save_file += frappe.db.get_value("Electronic Funds Transfer Bank Detail", self.bank_account, "branch_number").ljust(5) str_save_file += frappe.db.get_value("Electronic Funds Transfer Bank Detail", self.bank_account, "account_number").ljust(12) count = 0 total = 0.00 for supplier, dict_invoice in self.create_dict_from_list(self.get('items_eft')).items(): grand_total = 0.00 for invoice_name, grand_total_invoice in dict_invoice.items(): grand_total = grand_total + grand_total_invoice str_save_file += "\nC" str_save_file += "{:.2f}".format(grand_total).replace('.','').replace(',','').zfill(10) str_save_file += "0" str_save_file += frappe.db.get_value("Electronic Funds Transfer Supplier Information", {'supplier':supplier}, "institution_number").zfill(3) str_save_file += frappe.db.get_value("Electronic Funds Transfer Supplier Information", {'supplier':supplier}, "branch_number").zfill(5) str_save_file += frappe.db.get_value("Electronic Funds Transfer Supplier Information", {'supplier':supplier}, "account_number").ljust(12) supplier_without_accent = ''.join((c for c in unicodedata.normalize('NFD', supplier) if unicodedata.category(c) != 'Mn')) #supplier_without_accent = supplier str_save_file += supplier_without_accent.ljust(29)[:29] str_save_file += supplier_without_accent.ljust(19)[:19] count += 1 total += grand_total str_save_file += "\nYC" + str(count).zfill(8) + "{:.2f}".format(total).replace('.','').replace(',','').zfill(14) var_zero = 0 str_save_file += "\nZ" + str(var_zero).zfill(14) + str(var_zero).zfill(5) + "{:.2f}".format(total).replace('.','').replace(',','').zfill(14) + str(count).zfill(5) save_file("file-bank-transfer.txt", str_save_file, self.doctype, self.name, is_private=True) frappe.db.set(self, 'is_file_generated', True)
def create_items(args): for i in xrange(1, 6): item = args.get("item_" + str(i)) if item: item_group = args.get("item_group_" + str(i)) is_sales_item = args.get("is_sales_item_" + str(i)) is_purchase_item = args.get("is_purchase_item_" + str(i)) is_stock_item = item_group != _("Services") is_pro_applicable = item_group != _("Services") default_warehouse = "" if is_stock_item: default_warehouse = frappe.db.get_value( "Warehouse", filters={ "warehouse_name": _("Finished Goods") if is_sales_item else _("Stores"), "company": args.get("company_name").strip(), }, ) try: frappe.get_doc( { "doctype": "Item", "item_code": item, "item_name": item, "description": item, "is_sales_item": 1 if is_sales_item else 0, "is_purchase_item": 1 if is_purchase_item else 0, "show_in_website": 1, "is_stock_item": is_stock_item and 1 or 0, "is_pro_applicable": is_pro_applicable and 1 or 0, "item_group": item_group, "stock_uom": args.get("item_uom_" + str(i)), "default_warehouse": default_warehouse, } ).insert() if args.get("item_img_" + str(i)): item_image = args.get("item_img_" + str(i)).split(",") if len(item_image) == 3: filename, filetype, content = item_image fileurl = save_file(filename, content, "Item", item, decode=True).file_url frappe.db.set_value("Item", item, "image", fileurl) if args.get("item_price_" + str(i)): item_price = flt(args.get("item_price_" + str(i))) if is_sales_item: price_list_name = frappe.db.get_value("Price List", {"selling": 1}) make_item_price(item, price_list_name, item_price) if is_purchase_item: price_list_name = frappe.db.get_value("Price List", {"buying": 1}) make_item_price(item, price_list_name, item_price) except frappe.NameError: pass
def create_logo(args): if args.get("attach_logo"): attach_logo = args.get("attach_logo").split(",") if len(attach_logo)==3: filename, filetype, content = attach_logo fileurl = save_file(filename, content, "Website Settings", "Website Settings", decode=True).file_url frappe.db.set_value("Website Settings", "Website Settings", "brand_html", "<img src='{0}' style='max-width: 40px; max-height: 25px;'> {1}".format(fileurl, args.get("company_name").strip()))
def test_on_delete(self): file = frappe.get_doc("File", {"file_name":"file_copy.txt"}) file.delete() self.assertEqual(frappe.db.get_value("File", _("Home/Test Folder 1"), "file_size"), 0) folder = self.get_folder("Test Folder 3", "Home/Test Folder 1") self.saved_file = save_file('folder_copy.txt', "Testing folder copy example.", "", "", folder.name) folder = frappe.get_doc("File", "Home/Test Folder 1/Test Folder 3") self.assertRaises(frappe.ValidationError, folder.delete)
def create_letter_head(args): if args.get("attach_letterhead"): frappe.get_doc({ "doctype":"Letter Head", "letter_head_name": _("Standard"), "is_default": 1 }).insert() filename, filetype, content = args.get("attach_letterhead").split(",") fileurl = save_file(filename, content, "Letter Head", _("Standard"), decode=True).file_url frappe.db.set_value("Letter Head", _("Standard"), "content", "<img src='%s' style='max-width: 100%%;'>" % fileurl)
def qrcode_as_png(user, totp_uri): '''Save temporary Qrcode to server.''' from frappe.utils.file_manager import save_file folder = create_barcode_folder() png_file_name = '{}.png'.format(frappe.generate_hash(length=20)) file_obj = save_file(png_file_name, png_file_name, 'User', user, folder=folder) frappe.db.commit() file_url = get_url(file_obj.file_url) file_path = os.path.join(frappe.get_site_path('public', 'files'), file_obj.file_name) url = qrcreate(totp_uri) with open(file_path, 'w') as png_file: url.png(png_file, scale=8, module_color=[0, 0, 0, 180], background=[0xff, 0xff, 0xcc]) return file_url
def test_folder_copy(self): folder = self.get_folder("Test Folder 2", "Home") folder = self.get_folder("Test Folder 3", "Home/Test Folder 2") self.saved_file = save_file("folder_copy.txt", "Testing folder copy example.", "", "", folder.name) file_dict = [{"name": folder.name}] move_file(json.dumps(file_dict), "Home/Test Folder 1", folder.folder) file = frappe.get_doc("File", "/files/folder_copy.txt") self.assertEqual(_("Home/Test Folder 1/Test Folder 3"), file.folder) self.assertEqual(frappe.db.get_value("File", _("Home/Test Folder 1"), "file_size"), file.file_size) self.assertEqual(frappe.db.get_value("File", _("Home/Test Folder 2"), "file_size"), None)
def test_folder_copy(self): folder = self.get_folder("Test Folder 2", "Home") folder = self.get_folder("Test Folder 3", "Home/Test Folder 2") self.saved_file = save_file('folder_copy.txt', "Testing folder copy example.", "", "", folder.name) move_file([{"name": folder.name}], 'Home/Test Folder 1', folder.folder) file = frappe.get_doc("File", {"file_name":"folder_copy.txt"}) file_copy_txt = frappe.get_value("File", {"file_name":"file_copy.txt"}) if file_copy_txt: frappe.get_doc("File", file_copy_txt).delete() self.assertEqual(_("Home/Test Folder 1/Test Folder 3"), file.folder) self.assertEqual(frappe.db.get_value("File", _("Home/Test Folder 1"), "file_size"), file.file_size) self.assertEqual(frappe.db.get_value("File", _("Home/Test Folder 2"), "file_size"), 0)
def update_user_name(args): first_name, last_name = args.get('full_name', ''), '' if ' ' in first_name: first_name, last_name = first_name.split(' ', 1) if args.get("email"): if frappe.db.exists('User', args.get('email')): # running again return args['name'] = args.get("email") _mute_emails, frappe.flags.mute_emails = frappe.flags.mute_emails, True doc = frappe.get_doc({ "doctype":"User", "email": args.get("email"), "first_name": first_name, "last_name": last_name }) doc.flags.no_welcome_mail = True doc.insert() frappe.flags.mute_emails = _mute_emails update_password(args.get("email"), args.get("password")) elif first_name: args.update({ "name": frappe.session.user, "first_name": first_name, "last_name": last_name }) frappe.db.sql("""update `tabUser` SET first_name=%(first_name)s, last_name=%(last_name)s WHERE name=%(name)s""", args) if args.get("attach_user"): attach_user = args.get("attach_user").split(",") if len(attach_user)==3: filename, filetype, content = attach_user fileurl = save_file(filename, content, "User", args.get("name"), decode=True).file_url frappe.db.set_value("User", args.get("name"), "user_image", fileurl) if args.get('name'): add_all_roles_to(args.get("name"))
def save_attachments_in_doc(self, doc): """Save email attachments in given document.""" from frappe.utils.file_manager import save_file, MaxFileSizeReachedError saved_attachments = [] for attachment in self.attachments: try: file_data = save_file(attachment["fname"], attachment["fcontent"], doc.doctype, doc.name) saved_attachments.append(file_data.file_name) self.file_name_map[file_data.file_name] = file_data.file_url except MaxFileSizeReachedError: # WARNING: bypass max file size exception pass except frappe.DuplicateEntryError: # same file attached twice?? pass return saved_attachments
def save_attachments_in_doc(self, doc): """Save email attachments in given document.""" saved_attachments = [] for attachment in self.attachments: try: file_data = save_file(attachment['fname'], attachment['fcontent'], doc.doctype, doc.name, is_private=1) saved_attachments.append(file_data) if attachment['fname'] in self.cid_map: self.cid_map[file_data.name] = self.cid_map[attachment['fname']] except MaxFileSizeReachedError: # WARNING: bypass max file size exception pass except frappe.DuplicateEntryError: # same file attached twice?? pass return saved_attachments
def process_picture(post, picture_name, picture): from frappe.templates.generators.website_group import clear_cache post.picture_url = save_file(picture_name, picture, "Post", post.name, decode=True).file_url frappe.db.set_value("Post", post.name, "picture_url", post.picture_url) clear_cache(website_group=post.website_group)
def accept(): args = frappe.form_dict files = [] web_form = frappe.get_doc("Web Form", args.web_form) if args.doctype != web_form.doc_type: frappe.throw(_("Invalid Request")) elif args.name and not web_form.allow_edit: frappe.throw(_("You are not allowed to update this Web Form Document")) if args.name: # update doc = frappe.get_doc(args.doctype, args.name) else: # insert doc = frappe.new_doc(args.doctype) # set values for fieldname, value in args.iteritems(): if fieldname not in ("web_form", "cmd", "owner"): if value and value.startswith("{"): try: filedata = json.loads(value) if "__file_attachment" in filedata: files.append((fieldname, filedata)) continue except ValueError: pass doc.set(fieldname, value) if args.name: if has_web_form_permission(doc.doctype, doc.name, "write"): doc.save(ignore_permissions=True) else: # only if permissions are present doc.save() else: # insert if web_form.login_required and frappe.session.user=="Guest": frappe.throw(_("You must login to submit this form")) doc.insert(ignore_permissions = True) # add files if files: for f in files: fieldname, filedata = f # remove earlier attachmed file (if exists) if doc.get(fieldname): remove_file_by_url(doc.get(fieldname), doc.doctype, doc.name) # save new file filedoc = save_file(filedata["filename"], filedata["dataurl"], doc.doctype, doc.name, decode=True) # update values doc.set(fieldname, filedoc.file_url) doc.save()
def accept(web_form, data, for_payment=False): '''Save the web form''' data = frappe._dict(json.loads(data)) files = [] files_to_delete = [] web_form = frappe.get_doc("Web Form", web_form) if data.doctype != web_form.doc_type: frappe.throw(_("Invalid Request")) elif data.name and not web_form.allow_edit: frappe.throw(_("You are not allowed to update this Web Form Document")) frappe.flags.in_web_form = True if data.name: # update doc = frappe.get_doc(data.doctype, data.name) else: # insert doc = frappe.new_doc(data.doctype) # set values for fieldname, value in iteritems(data): if value and isinstance(value, dict): try: if "__file_attachment" in value: files.append((fieldname, value)) continue if '__no_attachment' in value: files_to_delete.append(doc.get(fieldname)) value = '' except ValueError: pass doc.set(fieldname, value) if for_payment: web_form.validate_mandatory(doc) doc.run_method('validate_payment') if doc.name: if has_web_form_permission(doc.doctype, doc.name, "write"): doc.save(ignore_permissions=True) else: # only if permissions are present doc.save() else: # insert if web_form.login_required and frappe.session.user=="Guest": frappe.throw(_("You must login to submit this form")) doc.insert(ignore_permissions = True) # add files if files: for f in files: fieldname, filedata = f # remove earlier attached file (if exists) if doc.get(fieldname): remove_file_by_url(doc.get(fieldname), doc.doctype, doc.name) # save new file filedoc = save_file(filedata["filename"], filedata["dataurl"], doc.doctype, doc.name, decode=True) # update values doc.set(fieldname, filedoc.file_url) doc.save() if files_to_delete: for f in files_to_delete: if f: remove_file_by_url(f, doc.doctype, doc.name) frappe.flags.web_form_doc = doc if for_payment: return web_form.get_payment_gateway_url(doc) else: return doc.name
def upload_file(self): self.saved_file = save_file('file_copy.txt', "Testing file copy example.",\ "", "", self.get_folder("Test Folder 1", "Home").name) self.saved_filename = get_files_path(self.saved_file.file_name)
def store_file(file_name, image_data, ps_doctype, ps_name): frappe.msgprint(str(file_name)) save_file(file_name, image_data, ps_doctype, ps_name, is_private=1)
def upload(rows = None, submit_after_import=None, ignore_encoding_errors=False, no_email=True, overwrite=None, update_only = None, ignore_links=False, pre_process=None, via_console=False, from_data_import="No", skip_errors = True, data_import_doc=None, validate_template=False, user=None): """upload data""" # for translations if user: frappe.cache().hdel("lang", user) frappe.set_user_lang(user) if data_import_doc and isinstance(data_import_doc, string_types): data_import_doc = frappe.get_doc("Data Import", data_import_doc) if data_import_doc and from_data_import == "Yes": no_email = data_import_doc.no_email ignore_encoding_errors = data_import_doc.ignore_encoding_errors update_only = data_import_doc.only_update submit_after_import = data_import_doc.submit_after_import overwrite = data_import_doc.overwrite skip_errors = data_import_doc.skip_errors else: # extra input params params = json.loads(frappe.form_dict.get("params") or '{}') if params.get("submit_after_import"): submit_after_import = True if params.get("ignore_encoding_errors"): ignore_encoding_errors = True if not params.get("no_email"): no_email = False if params.get('update_only'): update_only = True if params.get('from_data_import'): from_data_import = params.get('from_data_import') if not params.get('skip_errors'): skip_errors = params.get('skip_errors') frappe.flags.in_import = True frappe.flags.mute_emails = no_email def get_data_keys_definition(): return get_data_keys() def bad_template(): frappe.throw(_("Please do not change the rows above {0}").format(get_data_keys_definition().data_separator)) def check_data_length(): if not data: frappe.throw(_("No data found in the file. Please reattach the new file with data.")) def get_start_row(): for i, row in enumerate(rows): if row and row[0]==get_data_keys_definition().data_separator: return i+1 bad_template() def get_header_row(key): return get_header_row_and_idx(key)[0] def get_header_row_and_idx(key): for i, row in enumerate(header): if row and row[0]==key: return row, i return [], -1 def filter_empty_columns(columns): empty_cols = list(filter(lambda x: x in ("", None), columns)) if empty_cols: if columns[-1*len(empty_cols):] == empty_cols: # filter empty columns if they exist at the end columns = columns[:-1*len(empty_cols)] else: frappe.msgprint(_("Please make sure that there are no empty columns in the file."), raise_exception=1) return columns def make_column_map(): doctype_row, row_idx = get_header_row_and_idx(get_data_keys_definition().doctype) if row_idx == -1: # old style return dt = None for i, d in enumerate(doctype_row[1:]): if d not in ("~", "-"): if d and doctype_row[i] in (None, '' ,'~', '-', _("DocType") + ":"): dt, parentfield = d, None # xls format truncates the row, so it may not have more columns if len(doctype_row) > i+2: parentfield = doctype_row[i+2] doctypes.append((dt, parentfield)) column_idx_to_fieldname[(dt, parentfield)] = {} column_idx_to_fieldtype[(dt, parentfield)] = {} if dt: column_idx_to_fieldname[(dt, parentfield)][i+1] = rows[row_idx + 2][i+1] column_idx_to_fieldtype[(dt, parentfield)][i+1] = rows[row_idx + 4][i+1] def get_doc(start_idx): if doctypes: doc = {} attachments = [] last_error_row_idx = None for idx in range(start_idx, len(rows)): last_error_row_idx = idx # pylint: disable=W0612 if (not doc) or main_doc_empty(rows[idx]): for dt, parentfield in doctypes: d = {} for column_idx in column_idx_to_fieldname[(dt, parentfield)]: try: fieldname = column_idx_to_fieldname[(dt, parentfield)][column_idx] fieldtype = column_idx_to_fieldtype[(dt, parentfield)][column_idx] if not fieldname or not rows[idx][column_idx]: continue d[fieldname] = rows[idx][column_idx] if fieldtype in ("Int", "Check"): d[fieldname] = cint(d[fieldname]) elif fieldtype in ("Float", "Currency", "Percent"): d[fieldname] = flt(d[fieldname]) elif fieldtype == "Date": if d[fieldname] and isinstance(d[fieldname], string_types): d[fieldname] = getdate(parse_date(d[fieldname])) elif fieldtype == "Datetime": if d[fieldname]: if " " in d[fieldname]: _date, _time = d[fieldname].split() else: _date, _time = d[fieldname], '00:00:00' _date = parse_date(d[fieldname]) d[fieldname] = get_datetime(_date + " " + _time) else: d[fieldname] = None elif fieldtype in ("Image", "Attach Image", "Attach"): # added file to attachments list attachments.append(d[fieldname]) elif fieldtype in ("Link", "Dynamic Link", "Data") and d[fieldname]: # as fields can be saved in the number format(long type) in data import template d[fieldname] = cstr(d[fieldname]) except IndexError: pass # scrub quotes from name and modified if d.get("name") and d["name"].startswith('"'): d["name"] = d["name"][1:-1] if sum([0 if not val else 1 for val in d.values()]): d['doctype'] = dt if dt == doctype: doc.update(d) else: if not overwrite and doc.get("name"): d['parent'] = doc["name"] d['parenttype'] = doctype d['parentfield'] = parentfield doc.setdefault(d['parentfield'], []).append(d) else: break return doc, attachments, last_error_row_idx else: doc = frappe._dict(zip(columns, rows[start_idx][1:])) doc['doctype'] = doctype return doc, [], None # used in testing whether a row is empty or parent row or child row # checked only 3 first columns since first two columns can be blank for example the case of # importing the item variant where item code and item name will be blank. def main_doc_empty(row): if row: for i in range(3,0,-1): if len(row) > i and row[i]: return False return True def validate_naming(doc): autoname = frappe.get_meta(doctype).autoname if autoname: if autoname[0:5] == 'field': autoname = autoname[6:] elif autoname == 'naming_series:': autoname = 'naming_series' else: return True if (autoname not in doc) or (not doc[autoname]): from frappe.model.base_document import get_controller if not hasattr(get_controller(doctype), "autoname"): frappe.throw(_("{0} is a mandatory field".format(autoname))) return True users = frappe.db.sql_list("select name from tabUser") def prepare_for_insert(doc): # don't block data import if user is not set # migrating from another system if not doc.owner in users: doc.owner = frappe.session.user if not doc.modified_by in users: doc.modified_by = frappe.session.user def is_valid_url(url): is_valid = False if url.startswith("/files") or url.startswith("/private/files"): url = get_url(url) try: r = requests.get(url) is_valid = True if r.status_code == 200 else False except Exception: pass return is_valid def attach_file_to_doc(doctype, docname, file_url): # check if attachment is already available # check if the attachement link is relative or not if not file_url: return if not is_valid_url(file_url): return files = frappe.db.sql("""Select name from `tabFile` where attached_to_doctype='{doctype}' and attached_to_name='{docname}' and (file_url='{file_url}' or thumbnail_url='{file_url}')""".format( doctype=doctype, docname=docname, file_url=file_url )) if files: # file is already attached return save_url(file_url, None, doctype, docname, "Home/Attachments", 0) # header filename, file_extension = ['',''] if not rows: from frappe.utils.file_manager import get_file # get_file_doc fname, fcontent = get_file(data_import_doc.import_file) filename, file_extension = os.path.splitext(fname) if file_extension == '.xlsx' and from_data_import == 'Yes': from frappe.utils.xlsxutils import read_xlsx_file_from_attached_file rows = read_xlsx_file_from_attached_file(file_id=data_import_doc.import_file) elif file_extension == '.csv': from frappe.utils.csvutils import read_csv_content rows = read_csv_content(fcontent, ignore_encoding_errors) else: frappe.throw(_("Unsupported File Format")) start_row = get_start_row() header = rows[:start_row] data = rows[start_row:] try: doctype = get_header_row(get_data_keys_definition().main_table)[1] columns = filter_empty_columns(get_header_row(get_data_keys_definition().columns)[1:]) except: frappe.throw(_("Cannot change header content")) doctypes = [] column_idx_to_fieldname = {} column_idx_to_fieldtype = {} if skip_errors: data_rows_with_error = header if submit_after_import and not cint(frappe.db.get_value("DocType", doctype, "is_submittable")): submit_after_import = False parenttype = get_header_row(get_data_keys_definition().parent_table) if len(parenttype) > 1: parenttype = parenttype[1] # check permissions if not frappe.permissions.can_import(parenttype or doctype): frappe.flags.mute_emails = False return {"messages": [_("Not allowed to Import") + ": " + _(doctype)], "error": True} # Throw expception in case of the empty data file check_data_length() make_column_map() total = len(data) if validate_template: if total: data_import_doc.total_rows = total return True if overwrite==None: overwrite = params.get('overwrite') # delete child rows (if parenttype) parentfield = None if parenttype: parentfield = get_parent_field(doctype, parenttype) if overwrite: delete_child_rows(data, doctype) import_log = [] def log(**kwargs): if via_console: print((kwargs.get("title") + kwargs.get("message")).encode('utf-8')) else: import_log.append(kwargs) def as_link(doctype, name): if via_console: return "{0}: {1}".format(doctype, name) else: return getlink(doctype, name) # publish realtime task update def publish_progress(achieved, reload=False): if data_import_doc: frappe.publish_realtime("data_import_progress", {"progress": str(int(100.0*achieved/total)), "data_import": data_import_doc.name, "reload": reload}, user=frappe.session.user) error_flag = rollback_flag = False batch_size = frappe.conf.data_import_batch_size or 1000 for batch_start in range(0, total, batch_size): batch = data[batch_start:batch_start + batch_size] for i, row in enumerate(batch): # bypass empty rows if main_doc_empty(row): continue row_idx = i + start_row doc = None publish_progress(i) try: doc, attachments, last_error_row_idx = get_doc(row_idx) validate_naming(doc) if pre_process: pre_process(doc) original = None if parentfield: parent = frappe.get_doc(parenttype, doc["parent"]) doc = parent.append(parentfield, doc) parent.save() else: if overwrite and doc.get("name") and frappe.db.exists(doctype, doc["name"]): original = frappe.get_doc(doctype, doc["name"]) original_name = original.name original.update(doc) # preserve original name for case sensitivity original.name = original_name original.flags.ignore_links = ignore_links original.save() doc = original else: if not update_only: doc = frappe.get_doc(doc) prepare_for_insert(doc) doc.flags.ignore_links = ignore_links doc.insert() if attachments: # check file url and create a File document for file_url in attachments: attach_file_to_doc(doc.doctype, doc.name, file_url) if submit_after_import: doc.submit() # log errors if parentfield: log(**{"row": doc.idx, "title": 'Inserted row for "%s"' % (as_link(parenttype, doc.parent)), "link": get_url_to_form(parenttype, doc.parent), "message": 'Document successfully saved', "indicator": "green"}) elif submit_after_import: log(**{"row": row_idx + 1, "title":'Submitted row for "%s"' % (as_link(doc.doctype, doc.name)), "message": "Document successfully submitted", "link": get_url_to_form(doc.doctype, doc.name), "indicator": "blue"}) elif original: log(**{"row": row_idx + 1,"title":'Updated row for "%s"' % (as_link(doc.doctype, doc.name)), "message": "Document successfully updated", "link": get_url_to_form(doc.doctype, doc.name), "indicator": "green"}) elif not update_only: log(**{"row": row_idx + 1, "title":'Inserted row for "%s"' % (as_link(doc.doctype, doc.name)), "message": "Document successfully saved", "link": get_url_to_form(doc.doctype, doc.name), "indicator": "green"}) else: log(**{"row": row_idx + 1, "title":'Ignored row for %s' % (row[1]), "link": None, "message": "Document updation ignored", "indicator": "orange"}) except Exception as e: error_flag = True # build error message if frappe.local.message_log: err_msg = "\n".join(['<p class="border-bottom small">{}</p>'.format(json.loads(msg).get('message')) for msg in frappe.local.message_log]) else: err_msg = '<p class="border-bottom small">{}</p>'.format(cstr(e)) error_trace = frappe.get_traceback() if error_trace: error_log_doc = frappe.log_error(error_trace) error_link = get_url_to_form("Error Log", error_log_doc.name) else: error_link = None log(**{ "row": row_idx + 1, "title": 'Error for row %s' % (len(row)>1 and frappe.safe_decode(row[1]) or ""), "message": err_msg, "indicator": "red", "link":error_link }) # data with error to create a new file # include the errored data in the last row as last_error_row_idx will not be updated for the last row if skip_errors: if last_error_row_idx == len(rows)-1: last_error_row_idx = len(rows) data_rows_with_error += rows[row_idx:last_error_row_idx] else: rollback_flag = True finally: frappe.local.message_log = [] start_row += batch_size if rollback_flag: frappe.db.rollback() else: frappe.db.commit() frappe.flags.mute_emails = False frappe.flags.in_import = False log_message = {"messages": import_log, "error": error_flag} if data_import_doc: data_import_doc.log_details = json.dumps(log_message) import_status = None if error_flag and data_import_doc.skip_errors and len(data) != len(data_rows_with_error): import_status = "Partially Successful" # write the file with the faulty row from frappe.utils.file_manager import save_file file_name = 'error_' + filename + file_extension if file_extension == '.xlsx': from frappe.utils.xlsxutils import make_xlsx xlsx_file = make_xlsx(data_rows_with_error, "Data Import Template") file_data = xlsx_file.getvalue() else: from frappe.utils.csvutils import to_csv file_data = to_csv(data_rows_with_error) error_data_file = save_file(file_name, file_data, "Data Import", data_import_doc.name, "Home/Attachments") data_import_doc.error_file = error_data_file.file_url elif error_flag: import_status = "Failed" else: import_status = "Successful" data_import_doc.import_status = import_status data_import_doc.save() if data_import_doc.import_status in ["Successful", "Partially Successful"]: data_import_doc.submit() publish_progress(100, True) else: publish_progress(0, True) frappe.db.commit() else: return log_message