def send(self): # send email only to enabled users valid_users = [p[0] for p in frappe.db.sql("""select name from `tabUser` where enabled=1""")] recipients = list(filter(lambda r: r in valid_users, self.recipient_list.split("\n"))) original_user = frappe.session.user if recipients: for user_id in recipients: frappe.set_user(user_id) frappe.set_user_lang(user_id) msg_for_this_recipient = self.get_msg_html() if msg_for_this_recipient: frappe.sendmail( recipients=user_id, subject=_("{0} Digest").format(self.frequency), message=msg_for_this_recipient, reference_doctype = self.doctype, reference_name = self.name, unsubscribe_message = _("Unsubscribe from this Email Digest")) frappe.set_user(original_user) frappe.set_user_lang(original_user)
def send_event_digest(): today = nowdate() for user in frappe.db.sql("""select name, email, language from tabUser where ifnull(enabled,0)=1 and user_type='System User' and name not in ({})""".format(", ".join( ["%s"] * len(STANDARD_USERS))), STANDARD_USERS, as_dict=1): events = get_events(today, today, user.name, for_reminder=True) if events: text = "" frappe.set_user_lang(user.name, user.language) text = "<h3>" + frappe._("Events In Today's Calendar") + "</h3>" for e in events: if e.all_day: e.starts_on = "All Day" text += "<h4>%(starts_on)s: %(subject)s</h4><p>%(description)s</p>" % e text += '<p style="color: #888; font-size: 80%; margin-top: 20px; padding-top: 10px; border-top: 1px solid #eee;">'\ + frappe._("Daily Event Digest is sent for Calendar Events where reminders are set.")+'</p>' from frappe.utils.email_lib import sendmail sendmail(recipients=user.email, subject=frappe._("Upcoming Events for Today"), msg=text)
def get_bootinfo(): """build and return boot info""" frappe.set_user_lang(frappe.session.user) bootinfo = frappe._dict() hooks = frappe.get_hooks() doclist = [] # user get_user(bootinfo) # system info bootinfo['sysdefaults'] = frappe.defaults.get_defaults() bootinfo['server_date'] = frappe.utils.nowdate() if frappe.session['user'] != 'Guest': bootinfo['user_info'] = get_fullnames() bootinfo['sid'] = frappe.session['sid']; # home page bootinfo.modules = {} for app in frappe.get_installed_apps(): try: bootinfo.modules.update(frappe.get_attr(app + ".config.desktop.get_data")() or {}) except ImportError: pass except AttributeError: pass bootinfo.module_app = frappe.local.module_app bootinfo.hidden_modules = frappe.db.get_global("hidden_modules") bootinfo.doctype_icons = dict(frappe.db.sql("""select name, icon from tabDocType where ifnull(icon,'')!=''""")) bootinfo.single_types = frappe.db.sql_list("""select name from tabDocType where ifnull(issingle,0)=1""") add_home_page(bootinfo, doclist) bootinfo.page_info = get_allowed_pages() load_translations(bootinfo) add_timezone_info(bootinfo) load_conf_settings(bootinfo) load_print(bootinfo, doclist) doclist.extend(get_meta_bundle("Page")) bootinfo.home_folder = frappe.db.get_value("File", {"is_home_folder": 1}) # ipinfo if frappe.session['data'].get('ipinfo'): bootinfo['ipinfo'] = frappe.session['data']['ipinfo'] # add docs bootinfo['docs'] = doclist for method in hooks.boot_session or []: frappe.get_attr(method)(bootinfo) if bootinfo.lang: bootinfo.lang = unicode(bootinfo.lang) bootinfo['versions'] = {k: v['version'] for k, v in get_versions().items()} bootinfo.error_report_email = frappe.get_hooks("error_report_email") bootinfo.calendars = sorted(frappe.get_hooks("calendars")) return bootinfo
def run(): frappe.set_user("*****@*****.**") frappe.set_user_lang("fr") for i in range(random.randint(1,7)): if random.random() < 0.5: make_item_booking()
def get_bootinfo(): """build and return boot info""" frappe.set_user_lang(frappe.session.user) bootinfo = frappe._dict() hooks = frappe.get_hooks() doclist = [] # user get_user(bootinfo) # system info bootinfo.sysdefaults = frappe.defaults.get_defaults() bootinfo.server_date = frappe.utils.nowdate() if frappe.session['user'] != 'Guest': bootinfo.user_info = get_fullnames() bootinfo.sid = frappe.session['sid'] bootinfo.modules = {} bootinfo.module_list = [] load_desktop_icons(bootinfo) bootinfo.letter_heads = get_letter_heads() bootinfo.active_domains = frappe.get_active_domains() bootinfo.all_domains = [d.get("name") for d in frappe.get_all("Domain")] bootinfo.module_app = frappe.local.module_app bootinfo.single_types = frappe.db.sql_list("""select name from tabDocType where issingle=1""") add_home_page(bootinfo, doclist) bootinfo.page_info = get_allowed_pages() load_translations(bootinfo) add_timezone_info(bootinfo) load_conf_settings(bootinfo) load_print(bootinfo, doclist) doclist.extend(get_meta_bundle("Page")) bootinfo.home_folder = frappe.db.get_value("File", {"is_home_folder": 1}) # ipinfo if frappe.session.data.get('ipinfo'): bootinfo.ipinfo = frappe.session['data']['ipinfo'] # add docs bootinfo.docs = doclist for method in hooks.boot_session or []: frappe.get_attr(method)(bootinfo) if bootinfo.lang: bootinfo.lang = unicode(bootinfo.lang) bootinfo.versions = {k: v['version'] for k, v in get_versions().items()} bootinfo.error_report_email = frappe.get_hooks("error_report_email") bootinfo.calendars = sorted(frappe.get_hooks("calendars")) bootinfo.treeviews = frappe.get_hooks("treeviews") or [] bootinfo.lang_dict = get_lang_dict() bootinfo.feedback_triggers = get_enabled_feedback_trigger() bootinfo.gsuite_enabled = get_gsuite_status() bootinfo.update(get_email_accounts(user=frappe.session.user)) return bootinfo
def send(self): # send email only to enabled users valid_users = [ p[0] for p in frappe.db.sql("""select name from `tabUser` where enabled=1""") ] recipients = list( filter(lambda r: r in valid_users, self.recipient_list.split("\n"))) original_user = frappe.session.user if recipients: for user_id in recipients: frappe.set_user(user_id) frappe.set_user_lang(user_id) msg_for_this_recipient = self.get_msg_html() if msg_for_this_recipient: frappe.sendmail(recipients=user_id, subject=_("{0} Digest").format( self.frequency), message=msg_for_this_recipient, reference_doctype=self.doctype, reference_name=self.name, unsubscribe_message=_( "Unsubscribe from this Email Digest")) frappe.set_user(original_user) frappe.set_user_lang(original_user)
def run_projects(current_date): frappe.set_user(frappe.db.get_global('demo_projects_user')) frappe.set_user_lang(frappe.db.get_global('demo_projects_user')) if frappe.db.get_global('demo_projects_user'): make_project(current_date) make_timesheet_for_projects(current_date) close_tasks(current_date)
def work(): frappe.set_user(frappe.db.get_global('demo_hr_user')) frappe.set_user_lang(frappe.db.get_global('demo_hr_user')) year, month = frappe.flags.current_date.strftime("%Y-%m").split("-") setup_department_approvers() mark_attendance() make_leave_application() # payroll entry if not frappe.db.sql('select name from `tabSalary Slip` where month(adddate(start_date, interval 1 month))=month(curdate())'): # based on frequency payroll_entry = get_payroll_entry() payroll_entry.salary_slip_based_on_timesheet = 0 payroll_entry.save() payroll_entry.create_salary_slips() payroll_entry.submit_salary_slips() payroll_entry.make_accrual_jv_entry() payroll_entry.submit() # payroll_entry.make_journal_entry(reference_date=frappe.flags.current_date, # reference_number=random_string(10)) # based on timesheet payroll_entry = get_payroll_entry() payroll_entry.salary_slip_based_on_timesheet = 1 payroll_entry.save() payroll_entry.create_salary_slips() payroll_entry.submit_salary_slips() payroll_entry.make_accrual_jv_entry() payroll_entry.submit() # payroll_entry.make_journal_entry(reference_date=frappe.flags.current_date, # reference_number=random_string(10)) if frappe.db.get_global('demo_hr_user'): make_timesheet_records() #expense claim expense_claim = frappe.new_doc("Expense Claim") expense_claim.extend('expenses', get_expenses()) expense_claim.employee = get_random("Employee") expense_claim.company = frappe.flags.company expense_claim.payable_account = get_payable_account(expense_claim.company) expense_claim.posting_date = frappe.flags.current_date expense_claim.expense_approver = frappe.db.get_global('demo_hr_user') expense_claim.save() rand = random.random() if rand < 0.4: update_sanctioned_amount(expense_claim) expense_claim.approval_status = 'Approved' expense_claim.submit() if random.randint(0, 1): #make journal entry against expense claim je = frappe.get_doc(make_bank_entry("Expense Claim", expense_claim.name)) je.posting_date = frappe.flags.current_date je.cheque_no = random_string(10) je.cheque_date = frappe.flags.current_date je.flags.ignore_permissions = 1 je.submit()
def get_bootinfo(): """build and return boot info""" frappe.set_user_lang(frappe.session.user) bootinfo = frappe._dict() hooks = frappe.get_hooks() doclist = [] # user get_user(bootinfo) # system info bootinfo['sysdefaults'] = frappe.defaults.get_defaults() bootinfo['server_date'] = frappe.utils.nowdate() bootinfo["send_print_in_body_and_attachment"] = frappe.db.get_value( "Outgoing Email Settings", None, "send_print_in_body_and_attachment") if frappe.session['user'] != 'Guest': bootinfo['user_info'] = get_fullnames() bootinfo['sid'] = frappe.session['sid'] # home page bootinfo.modules = {} for app in frappe.get_installed_apps(): try: bootinfo.modules.update( frappe.get_attr(app + ".config.desktop.get_data")() or {}) except ImportError: pass bootinfo.module_app = frappe.local.module_app bootinfo.hidden_modules = frappe.db.get_global("hidden_modules") bootinfo.doctype_icons = dict( frappe.db.sql("""select name, icon from tabDocType where ifnull(icon,'')!=''""")) bootinfo.doctype_icons.update( dict( frappe.db.sql("""select name, icon from tabPage where ifnull(icon,'')!=''"""))) add_home_page(bootinfo, doclist) add_allowed_pages(bootinfo) load_translations(bootinfo) load_conf_settings(bootinfo) # ipinfo if frappe.session['data'].get('ipinfo'): bootinfo['ipinfo'] = frappe.session['data']['ipinfo'] # add docs bootinfo['docs'] = doclist for method in hooks.boot_session or []: frappe.get_attr(method)(bootinfo) if bootinfo.lang: bootinfo.lang = unicode(bootinfo.lang) return bootinfo
def get_bootinfo(): """build and return boot info""" frappe.set_user_lang(frappe.session.user) bootinfo = frappe._dict() hooks = frappe.get_hooks() doclist = [] # user get_user(bootinfo) # system info bootinfo['sysdefaults'] = frappe.defaults.get_defaults() bootinfo['server_date'] = frappe.utils.nowdate() if frappe.session['user'] != 'Guest': bootinfo['user_info'] = get_fullnames() bootinfo['sid'] = frappe.session['sid']; # home page bootinfo.modules = {} for app in frappe.get_installed_apps(): try: bootinfo.modules.update(frappe.get_attr(app + ".config.desktop.get_data")() or {}) except ImportError: pass except AttributeError: pass bootinfo.module_app = frappe.local.module_app bootinfo.hidden_modules = frappe.db.get_global("hidden_modules") bootinfo.doctype_icons = dict(frappe.db.sql("""select name, icon from tabDocType where ifnull(icon,'')!=''""")) bootinfo.single_types = frappe.db.sql_list("""select name from tabDocType where ifnull(issingle,0)=1""") add_home_page(bootinfo, doclist) bootinfo.page_info = get_allowed_pages() load_translations(bootinfo) add_timezone_info(bootinfo) load_conf_settings(bootinfo) load_print(bootinfo, doclist) # ipinfo if frappe.session['data'].get('ipinfo'): bootinfo['ipinfo'] = frappe.session['data']['ipinfo'] # add docs bootinfo['docs'] = doclist for method in hooks.boot_session or []: frappe.get_attr(method)(bootinfo) if bootinfo.lang: bootinfo.lang = unicode(bootinfo.lang) bootinfo.error_report_email = frappe.get_hooks("error_report_email") bootinfo.default_background_image = "/assets/frappe/images/ui/into-the-dawn.jpg" return bootinfo
def get_bootinfo(): """build and return boot info""" frappe.set_user_lang(frappe.session.user) bootinfo = frappe._dict() hooks = frappe.get_hooks() doclist = [] # user get_user(bootinfo) # system info bootinfo.sysdefaults = frappe.defaults.get_defaults() bootinfo.server_date = frappe.utils.nowdate() if frappe.session['user'] != 'Guest': bootinfo.user_info = get_fullnames() bootinfo.sid = frappe.session['sid']; bootinfo.modules = {} bootinfo.module_list = [] load_desktop_icons(bootinfo) bootinfo.module_app = frappe.local.module_app bootinfo.single_types = frappe.db.sql_list("""select name from tabDocType where issingle=1""") add_home_page(bootinfo, doclist) bootinfo.page_info = get_allowed_pages() load_translations(bootinfo) add_timezone_info(bootinfo) load_conf_settings(bootinfo) load_print(bootinfo, doclist) doclist.extend(get_meta_bundle("Page")) bootinfo.home_folder = frappe.db.get_value("File", {"is_home_folder": 1}) # ipinfo if frappe.session.data.get('ipinfo'): bootinfo.ipinfo = frappe.session['data']['ipinfo'] # add docs bootinfo.docs = doclist for method in hooks.boot_session or []: frappe.get_attr(method)(bootinfo) if bootinfo.lang: bootinfo.lang = unicode(bootinfo.lang) bootinfo.versions = {k: v['version'] for k, v in get_versions().items()} bootinfo.error_report_email = frappe.get_hooks("error_report_email") bootinfo.calendars = sorted(frappe.get_hooks("calendars")) bootinfo.treeviews = frappe.get_hooks("treeviews") or [] bootinfo.email_accounts = frappe.get_all('User Emails', fields=['email_account', 'email_id'], filters=dict(parent=frappe.session.user), order_by='idx') bootinfo.lang_dict = get_lang_dict() return bootinfo
def work(): frappe.set_user(frappe.db.get_global('demo_manufacturing_user')) frappe.set_user_lang(frappe.db.get_global('demo_manufacturing_user')) make_purchase_receipt() make_delivery_note() make_stock_reconciliation() submit_draft_stock_entries() make_sales_return_records() make_purchase_return_records()
def before_import(self): # set user lang for translations frappe.cache().hdel("lang", frappe.session.user) frappe.set_user_lang(frappe.session.user) # set flags frappe.flags.in_import = True frappe.flags.mute_emails = self.data_import.mute_emails self.data_import.db_set("template_warnings", "")
def get_bootinfo(): """build and return boot info""" frappe.set_user_lang(frappe.session.user) bootinfo = frappe._dict() hooks = frappe.get_hooks() doclist = [] # user get_user(bootinfo) # system info bootinfo['sysdefaults'] = frappe.defaults.get_defaults() bootinfo['server_date'] = frappe.utils.nowdate() bootinfo["send_print_in_body_and_attachment"] = frappe.db.get_value("Outgoing Email Settings", None, "send_print_in_body_and_attachment") if frappe.session['user'] != 'Guest': bootinfo['user_info'] = get_fullnames() bootinfo['sid'] = frappe.session['sid']; # home page bootinfo.modules = {} for app in frappe.get_installed_apps(): try: bootinfo.modules.update(frappe.get_attr(app + ".config.desktop.data") or {}) except ImportError: pass bootinfo.module_app = frappe.local.module_app bootinfo.hidden_modules = frappe.db.get_global("hidden_modules") bootinfo.doctype_icons = dict(frappe.db.sql("""select name, icon from tabDocType where ifnull(icon,'')!=''""")) bootinfo.doctype_icons.update(dict(frappe.db.sql("""select name, icon from tabPage where ifnull(icon,'')!=''"""))) add_home_page(bootinfo, doclist) add_allowed_pages(bootinfo) load_translations(bootinfo) load_conf_settings(bootinfo) # ipinfo if frappe.session['data'].get('ipinfo'): bootinfo['ipinfo'] = frappe.session['data']['ipinfo'] # add docs bootinfo['docs'] = doclist for method in hooks.boot_session or []: frappe.get_attr(method)(bootinfo) if bootinfo.lang: bootinfo.lang = unicode(bootinfo.lang) return bootinfo
def verify_request(): woocommerce_settings = frappe.get_doc("Woocommerce Settings") sig = base64.b64encode( hmac.new(woocommerce_settings.secret.encode('utf8'), frappe.request.data, hashlib.sha256).digest()) if frappe.request.data and \ frappe.get_request_header("X-Wc-Webhook-Signature") and \ not sig == bytes(frappe.get_request_header("X-Wc-Webhook-Signature").encode()): frappe.throw(_("Unverified Webhook Data")) frappe.set_user(woocommerce_settings.creation_user) frappe.set_user_lang(woocommerce_settings.creation_user)
def get_bootinfo(): """build and return boot info""" frappe.set_user_lang(frappe.session.user) bootinfo = frappe._dict() hooks = frappe.get_hooks() doclist = [] # user get_user(bootinfo) # system info bootinfo['sysdefaults'] = frappe.defaults.get_defaults() bootinfo['server_date'] = frappe.utils.nowdate() if frappe.session['user'] != 'Guest': bootinfo['user_info'] = get_fullnames() bootinfo['sid'] = frappe.session['sid'] bootinfo.modules = {} bootinfo.module_list = [] load_desktop_icons(bootinfo) bootinfo.module_app = frappe.local.module_app bootinfo.single_types = frappe.db.sql_list( """select name from tabDocType where issingle=1""") add_home_page(bootinfo, doclist) bootinfo.page_info = get_allowed_pages() load_translations(bootinfo) add_timezone_info(bootinfo) load_conf_settings(bootinfo) load_print(bootinfo, doclist) doclist.extend(get_meta_bundle("Page")) bootinfo.home_folder = frappe.db.get_value("File", {"is_home_folder": 1}) # ipinfo if frappe.session['data'].get('ipinfo'): bootinfo['ipinfo'] = frappe.session['data']['ipinfo'] # add docs bootinfo['docs'] = doclist for method in hooks.boot_session or []: frappe.get_attr(method)(bootinfo) if bootinfo.lang: bootinfo.lang = unicode(bootinfo.lang) bootinfo['versions'] = {k: v['version'] for k, v in get_versions().items()} bootinfo.error_report_email = frappe.get_hooks("error_report_email") bootinfo.calendars = sorted(frappe.get_hooks("calendars")) bootinfo["lang_dict"] = get_lang_dict() return bootinfo
def run(): frappe.set_user("*****@*****.**") frappe.set_user_lang("fr") if random.random() <= 0.6: sales_orders = frappe.get_all("Sales Order", filters={"per_billed": ("<", 100)}) for so in sales_orders[:random.randint(1, 5)]: try: si = frappe.get_doc(make_sales_invoice(so)) si.set_posting_time = True si.posting_date = frappe.flags.current_date si.payment_schedule = [] for d in si.get("items"): if not d.income_account: d.income_account = "Sales - {}".format(frappe.get_cached_value('Company', si.company, 'abbr')) si.insert() si.submit() frappe.db.commit() except frappe.ValidationError: pass except erpnext.accounts.utils.FiscalYearError: add_fiscal_year(frappe.flags.current_date) # TODO """ if random.random() <= 0.6: report = "Received Items to be Billed" for pr in list(set([r[0] for r in query_report.run(report)["result"] if r[0]!="Total"]))[:random.randint(1, 5)]: try: pi = frappe.get_doc(make_purchase_invoice(pr)) pi.set_posting_time = True pi.posting_date = frappe.flags.current_date pi.bill_no = random_string(6) pi.insert() pi.submit() frappe.db.commit() except frappe.ValidationError: pass """ if random.random() < 0.5: make_payment_entries("Sales Invoice", "Accounts Receivable") # TODO """
def send_summary(timespan): from frappe.utils.user import get_enabled_system_users from frappe.social.doctype.energy_point_settings.energy_point_settings import is_energy_point_enabled if not is_energy_point_enabled(): return from_date = frappe.utils.add_to_date(None, weeks=-1) if timespan == 'Monthly': from_date = frappe.utils.add_to_date(None, months=-1) user_points = get_user_energy_and_review_points(from_date=from_date, as_dict=False) # do not send report if no activity found if not user_points or not user_points[0].energy_points: return from_date = getdate(from_date) to_date = getdate() settings = {x["name"]: x["energy_points_summary"] for x in frappe.get_all("User", \ filters={"user_type": "System User", "enabled": 1}, fields=["name", "energy_points_summary"])} all_users = [ user for user in get_enabled_system_users() if settings.get(user["name"]) == 1 ] for user in all_users: frappe.set_user_lang(user.name) frappe.sendmail( subject=_('{} energy points summary').format(_(timespan)), recipients=user.email, template="energy_points_summary", args={ 'top_performer': user_points[0], 'top_reviewer': max(user_points, key=lambda x: x['given_points']), 'standings': user_points[:10], # top 10 'footer_message': get_footer_message(timespan).format(from_date, to_date) }) frappe.set_user_lang(frappe.session.user)
def send_event_digest(): today = nowdate() for user in get_enabled_system_users(): events = get_events(today, today, user.name, for_reminder=True) if events: text = "" frappe.set_user_lang(user.name, user.language) text = "<h3>" + frappe._("Events In Today's Calendar") + "</h3>" for e in events: if e.all_day: e.starts_on = "All Day" text += "<h4>%(starts_on)s: %(subject)s</h4><p>%(description)s</p>" % e text += '<p style="color: #888; font-size: 80%; margin-top: 20px; padding-top: 10px; border-top: 1px solid #eee;">'\ + frappe._("Daily Event Digest is sent for Calendar Events where reminders are set.")+'</p>' frappe.sendmail(recipients=user.email, subject=frappe._("Upcoming Events for Today"), content = text)
def send_event_digest(): today = nowdate() for user in get_enabled_system_users(): events = get_events(today, today, user.name, for_reminder=True) if events: frappe.set_user_lang(user.name, user.language) for e in events: e.starts_on = format_datetime(e.starts_on, 'hh:mm a') if e.all_day: e.starts_on = "All Day" frappe.sendmail( recipients=user.email, subject=frappe._("Upcoming Events for Today"), template="upcoming_events", args={ 'events': events, }, header=[frappe._("Events in Today's Calendar"), 'blue'])
def work(): frappe.set_user(frappe.db.get_global('demo_accounts_user')) frappe.set_user_lang(frappe.db.get_global('demo_accounts_user')) # Enable booking asset depreciation entry automatically frappe.db.set_value("Accounts Settings", None, "book_asset_depreciation_entry_automatically", 1) # post depreciation entries as on today post_depreciation_entries() # scrap a random asset frappe.db.set_value("Company", "Wind Power", "disposal_account", _("Gain/Loss on Asset Disposal") + " - WP") asset = get_random_asset() scrap_asset(asset.name) # Sell a random asset sell_an_asset()
def send_event_digest(): today = nowdate() for user in get_enabled_system_users(): events = get_events(today, today, user.name, for_reminder=True) if events: frappe.set_user_lang(user.name, user.language) for e in events: e.starts_on = format_datetime(e.starts_on, 'hh:mm a') if e.all_day: e.starts_on = "All Day" frappe.sendmail( recipients=user.email, subject=frappe._("Upcoming Events for Today"), template="upcoming_events", args={ 'events': events, }, header=[frappe._("Events in Today's Calendar"), 'blue'] )
def make_item_booking(): user = get_random("User") item = get_random("Item", filters={"enable_item_booking": 1}) frappe.set_user(user) frappe.set_user_lang("fr") availabilities = get_availabilities(item, add_days(frappe.flags.current_date, 1), add_days(frappe.flags.current_date, 2)) if availabilities: availability = availabilities[random.randint(0, len(availabilities) - 1)] ib = frappe.get_doc({ "doctype": "Item Booking", "user": user, "item": item, "starts_on": availability.get("start"), "ends_on": availability.get("end"), "status": STATUSES[random.randint(0, 2)] }) ib.insert(ignore_permissions=True) frappe.db.commit()
def send_event_digest(): today = nowdate() for user in frappe.db.sql("""select name, email, language from tabUser where ifnull(enabled,0)=1 and user_type='System User' and name not in ({})""".format(", ".join(["%s"]*len(STANDARD_USERS))), STANDARD_USERS, as_dict=1): events = get_events(today, today, user.name, for_reminder=True) if events: text = "" frappe.set_user_lang(user.name, user.language) text = "<h3>" + frappe._("Events In Today's Calendar") + "</h3>" for e in events: if e.all_day: e.starts_on = "All Day" text += "<h4>%(starts_on)s: %(subject)s</h4><p>%(description)s</p>" % e text += '<p style="color: #888; font-size: 80%; margin-top: 20px; padding-top: 10px; border-top: 1px solid #eee;">'\ + frappe._("Daily Event Digest is sent for Calendar Events where reminders are set.")+'</p>' from frappe.utils.email_lib import sendmail sendmail(recipients=user.email, subject=frappe._("Upcoming Events for Today"), msg = text)
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
def run(): frappe.set_user("*****@*****.**") frappe.set_user_lang("fr") if random.random() < 0.6: report = "Items To Be Requested" for row in query_report.run(report)["result"][:random.randint(1, 5)]: item_code, qty = row[0], abs(row[-1]) mr = make_material_request(item_code, qty) if random.random() < 0.6: for mr in frappe.get_all('Material Request', filters={'material_request_type': 'Purchase', 'status': 'Open'}, limit=random.randint(1,6)): if not frappe.get_all('Request for Quotation', filters={'material_request': mr.name}, limit=1): rfq = make_request_for_quotation(mr.name) rfq.transaction_date = frappe.flags.current_date add_suppliers(rfq) rfq.save() rfq.submit() # Make suppier quotation from RFQ against each supplier. if random.random() < 0.6: for rfq in frappe.get_all('Request for Quotation', filters={'status': 'Open'}, limit=random.randint(1, 6)): if not frappe.get_all('Supplier Quotation', filters={'request_for_quotation': rfq.name}, limit=1): rfq = frappe.get_doc('Request for Quotation', rfq.name) for supplier in rfq.suppliers: supplier_quotation = make_quotation_from_rfq(rfq.name, supplier.supplier) supplier_quotation.save() supplier_quotation.submit() # get supplier details supplier = get_random("Supplier") company_currency = frappe.get_cached_value('Company', erpnext.get_default_company(), "default_currency") party_account_currency = get_party_account_currency("Supplier", supplier, erpnext.get_default_company()) if company_currency == party_account_currency: exchange_rate = 1 else: exchange_rate = get_exchange_rate(party_account_currency, company_currency, args="for_buying") # make supplier quotations if random.random() < 0.5: from erpnext.stock.doctype.material_request.material_request import make_supplier_quotation report = "Material Requests for which Supplier Quotations are not created" for row in query_report.run(report)["result"][:random.randint(1, 3)]: if row[0] != "Total": sq = frappe.get_doc(make_supplier_quotation(row[0])) sq.transaction_date = frappe.flags.current_date sq.supplier = supplier sq.currency = party_account_currency or company_currency sq.conversion_rate = exchange_rate sq.insert() sq.submit() frappe.db.commit() # make purchase orders if random.random() < 0.5: from erpnext.stock.doctype.material_request.material_request import make_purchase_order report = "Requested Items To Be Ordered" for row in query_report.run(report)["result"][:how_many("Purchase Order")]: if row[0] != "Total": try: po = frappe.get_doc(make_purchase_order(row[0])) po.supplier = supplier po.currency = party_account_currency or company_currency po.conversion_rate = exchange_rate po.transaction_date = frappe.flags.current_date po.insert() po.submit() except Exception: pass else: frappe.db.commit() if random.random() < 0.5: make_subcontract()
def run(): frappe.set_user("*****@*****.**") frappe.set_user_lang("fr") for i in range(random.randint(1, 7)): if random.random() < 0.5: make_opportunity() for i in range(random.randint(1, 7)): if random.random() < 0.5: make_quotation() try: lost_reason = frappe.get_doc({ "doctype": "Opportunity Lost Reason", "lost_reason": _("Did not ask") }) lost_reason.save(ignore_permissions=True) except frappe.exceptions.DuplicateEntryError: pass # lost quotations / inquiries if random.random() < 0.3: for i in range(random.randint(1, 3)): quotation = get_random('Quotation', doc=True) if quotation and quotation.status == 'Submitted': quotation.declare_order_lost([{ 'lost_reason': _('Did not ask') }]) for i in range(random.randint(1, 3)): opportunity = get_random('Opportunity', doc=True) if opportunity and opportunity.status in ('Open', 'Replied'): opportunity.declare_enquiry_lost([{ 'lost_reason': _('Did not ask') }]) for i in range(random.randint(1, 7)): if random.random() < 0.6: make_sales_order() if random.random() < 0.5: #make payment request against Sales Order sales_order_name = get_random("Sales Order", filters={"docstatus": 1}) try: if sales_order_name: so = frappe.get_doc("Sales Order", sales_order_name) if flt(so.per_billed) != 100: payment_request = make_payment_request( dt="Sales Order", dn=so.name, recipient_id=so.contact_email, submit_doc=True, mute_email=True, use_dummy_message=True) payment_entry = frappe.get_doc( make_payment_entry(payment_request.name)) payment_entry.posting_date = frappe.flags.current_date payment_entry.submit() except Exception: pass
def import_data(self): # set user lang for translations frappe.cache().hdel("lang", frappe.session.user) frappe.set_user_lang(frappe.session.user) if not self.console: self.data_import.db_set("template_warnings", "") # set flags frappe.flags.in_import = True frappe.flags.mute_emails = self.data_import.mute_emails # prepare a map for missing link field values self.prepare_missing_link_field_values() # parse docs from rows payloads = self.get_payloads_for_import() # dont import if there are non-ignorable warnings warnings = [w for w in self.warnings if w.get("type") != "info"] if warnings: if self.console: self.print_grouped_warnings(warnings) else: self.data_import.db_set("template_warnings", json.dumps(warnings)) frappe.publish_realtime( "data_import_refresh", {"data_import": self.data_import.name} ) return # setup import log if self.data_import.import_log: import_log = frappe.parse_json(self.data_import.import_log) else: import_log = [] # remove previous failures from import log import_log = [l for l in import_log if l.get("success") == True] # get successfully imported rows imported_rows = [] for log in import_log: log = frappe._dict(log) if log.success: imported_rows += log.row_indexes # start import total_payload_count = len(payloads) batch_size = frappe.conf.data_import_batch_size or 1000 for batch_index, batched_payloads in enumerate( frappe.utils.create_batch(payloads, batch_size) ): for i, payload in enumerate(batched_payloads): doc = payload.doc row_indexes = [row[0] for row in payload.rows] current_index = (i + 1) + (batch_index * batch_size) if set(row_indexes).intersection(set(imported_rows)): print("Skipping imported rows", row_indexes) if total_payload_count > 5: frappe.publish_realtime( "data_import_progress", { "current": current_index, "total": total_payload_count, "skipping": True, "data_import": self.data_import.name, }, ) continue try: start = timeit.default_timer() doc = self.process_doc(doc) processing_time = timeit.default_timer() - start eta = self.get_eta(current_index, total_payload_count, processing_time) if total_payload_count > 5: frappe.publish_realtime( "data_import_progress", { "current": current_index, "total": total_payload_count, "docname": doc.name, "data_import": self.data_import.name, "success": True, "row_indexes": row_indexes, "eta": eta, }, ) if self.console: update_progress_bar( "Importing {0} records".format(total_payload_count), current_index, total_payload_count, ) import_log.append( frappe._dict(success=True, docname=doc.name, row_indexes=row_indexes) ) # commit after every successful import frappe.db.commit() except Exception: import_log.append( frappe._dict( success=False, exception=frappe.get_traceback(), messages=frappe.local.message_log, row_indexes=row_indexes, ) ) frappe.clear_messages() # rollback if exception frappe.db.rollback() # set status failures = [l for l in import_log if l.get("success") == False] if len(failures) == total_payload_count: status = "Pending" elif len(failures) > 0: status = "Partial Success" else: status = "Success" if self.console: self.print_import_log(import_log) else: self.data_import.db_set("status", status) self.data_import.db_set("import_log", json.dumps(import_log)) frappe.flags.in_import = False frappe.flags.mute_emails = False frappe.publish_realtime("data_import_refresh", {"data_import": self.data_import.name}) return import_log
def get_bootinfo(): """build and return boot info""" frappe.set_user_lang(frappe.session.user) bootinfo = frappe._dict() hooks = frappe.get_hooks() doclist = [] # user get_user(bootinfo) # system info bootinfo.sitename = frappe.local.site bootinfo.sysdefaults = frappe.defaults.get_defaults() bootinfo.user_permissions = get_user_permissions() bootinfo.server_date = frappe.utils.nowdate() if frappe.session['user'] != 'Guest': bootinfo.user_info = get_fullnames() bootinfo.sid = frappe.session['sid']; bootinfo.modules = {} bootinfo.module_list = [] load_desktop_icons(bootinfo) bootinfo.letter_heads = get_letter_heads() bootinfo.active_domains = frappe.get_active_domains() bootinfo.all_domains = [d.get("name") for d in frappe.get_all("Domain")] bootinfo.module_app = frappe.local.module_app bootinfo.single_types = frappe.db.sql_list("""select name from tabDocType where issingle=1""") add_home_page(bootinfo, doclist) bootinfo.page_info = get_allowed_pages() load_translations(bootinfo) add_timezone_info(bootinfo) load_conf_settings(bootinfo) load_print(bootinfo, doclist) doclist.extend(get_meta_bundle("Page")) bootinfo.home_folder = frappe.db.get_value("File", {"is_home_folder": 1}) # ipinfo if frappe.session.data.get('ipinfo'): bootinfo.ipinfo = frappe.session['data']['ipinfo'] # add docs bootinfo.docs = doclist for method in hooks.boot_session or []: frappe.get_attr(method)(bootinfo) if bootinfo.lang: bootinfo.lang = text_type(bootinfo.lang) bootinfo.versions = {k: v['version'] for k, v in get_versions().items()} bootinfo.error_report_email = frappe.get_hooks("error_report_email") bootinfo.calendars = sorted(frappe.get_hooks("calendars")) bootinfo.treeviews = frappe.get_hooks("treeviews") or [] bootinfo.lang_dict = get_lang_dict() bootinfo.feedback_triggers = get_enabled_feedback_trigger() bootinfo.gsuite_enabled = get_gsuite_status() bootinfo.update(get_email_accounts(user=frappe.session.user)) return bootinfo
def work(): if random.random() < 0.3: return frappe.set_user(frappe.db.get_global('demo_manufacturing_user')) frappe.set_user_lang(frappe.db.get_global('demo_manufacturing_user')) if not frappe.get_all('Sales Order'): return from erpnext.projects.doctype.timesheet.timesheet import OverlapError ppt = frappe.new_doc("Production Plan") ppt.company = erpnext.get_default_company() # ppt.use_multi_level_bom = 1 #refactored ppt.get_items_from = "Sales Order" # ppt.purchase_request_for_warehouse = "Stores - WP" # refactored ppt.run_method("get_open_sales_orders") if not ppt.get("sales_orders"): return ppt.run_method("get_items") ppt.run_method("raise_material_requests") ppt.save() ppt.submit() ppt.run_method("raise_work_orders") frappe.db.commit() # submit work orders for pro in frappe.db.get_values("Work Order", {"docstatus": 0}, "name"): b = frappe.get_doc("Work Order", pro[0]) b.wip_warehouse = "Work in Progress - WP" b.submit() frappe.db.commit() # submit material requests for pro in frappe.db.get_values("Material Request", {"docstatus": 0}, "name"): b = frappe.get_doc("Material Request", pro[0]) b.submit() frappe.db.commit() # stores -> wip if random.random() < 0.4: for pro in query_report.run("Open Work Orders")[ "result"][:how_many("Stock Entry for WIP")]: make_stock_entry_from_pro(pro[0], "Material Transfer for Manufacture") # wip -> fg if random.random() < 0.4: for pro in query_report.run("Work Orders in Progress")[ "result"][:how_many("Stock Entry for FG")]: make_stock_entry_from_pro(pro[0], "Manufacture") for bom in frappe.get_all('BOM', fields=['item'], filters={'with_operations': 1}): pro_order = make_wo_order_test_record( item=bom.item, qty=2, source_warehouse=_("Stores") + " - WP", wip_warehouse=_("Work in Progress") + " - WP", fg_warehouse=_("Stores") + " - WP", company=erpnext.get_default_company(), stock_uom=frappe.db.get_value('Item', bom.item, 'stock_uom'), planned_start_date=get_datetime(frappe.flags.current_date)) # submit job card if random.random() < 0.4: submit_job_cards()
def get_bootinfo(): """build and return boot info""" frappe.set_user_lang(frappe.session.user) bootinfo = frappe._dict() hooks = frappe.get_hooks() doclist = [] # user get_user(bootinfo) # system info bootinfo["sysdefaults"] = frappe.defaults.get_defaults() bootinfo["server_date"] = frappe.utils.nowdate() if frappe.session["user"] != "Guest": bootinfo["user_info"] = get_fullnames() bootinfo["sid"] = frappe.session["sid"] # home page bootinfo.modules = {} for app in frappe.get_installed_apps(): try: bootinfo.modules.update(frappe.get_attr(app + ".config.desktop.get_data")() or {}) except ImportError: pass except AttributeError: pass bootinfo.module_app = frappe.local.module_app bootinfo.hidden_modules = frappe.db.get_global("hidden_modules") bootinfo.doctype_icons = dict( frappe.db.sql( """select name, icon from tabDocType where ifnull(icon,'')!=''""" ) ) bootinfo.single_types = frappe.db.sql_list("""select name from tabDocType where ifnull(issingle,0)=1""") add_home_page(bootinfo, doclist) bootinfo.page_info = get_allowed_pages() load_translations(bootinfo) add_timezone_info(bootinfo) load_conf_settings(bootinfo) load_print(bootinfo, doclist) doclist.extend(get_meta_bundle("Page")) # ipinfo if frappe.session["data"].get("ipinfo"): bootinfo["ipinfo"] = frappe.session["data"]["ipinfo"] # add docs bootinfo["docs"] = doclist for method in hooks.boot_session or []: frappe.get_attr(method)(bootinfo) if bootinfo.lang: bootinfo.lang = unicode(bootinfo.lang) bootinfo["versions"] = {k: v["version"] for k, v in get_versions().items()} bootinfo.error_report_email = frappe.get_hooks("error_report_email") bootinfo.default_background_image = get_url("/assets/frappe/images/ui/into-the-dawn.jpg") bootinfo.calendars = sorted(frappe.get_hooks("calendars")) return bootinfo
def get_bootinfo(): """build and return boot info""" frappe.set_user_lang(frappe.session.user) bootinfo = frappe._dict() hooks = frappe.get_hooks() doclist = [] # user get_user(bootinfo) # system info bootinfo.sitename = frappe.local.site bootinfo.sysdefaults = frappe.defaults.get_defaults() bootinfo.server_date = frappe.utils.nowdate() if frappe.session['user'] != 'Guest': bootinfo.user_info = get_user_info() bootinfo.sid = frappe.session['sid'] bootinfo.modules = {} bootinfo.module_list = [] load_desktop_data(bootinfo) bootinfo.letter_heads = get_letter_heads() bootinfo.active_domains = frappe.get_active_domains() bootinfo.all_domains = [d.get("name") for d in frappe.get_all("Domain")] add_layouts(bootinfo) bootinfo.module_app = frappe.local.module_app bootinfo.single_types = [ d.name for d in frappe.get_all('DocType', {'issingle': 1}) ] bootinfo.nested_set_doctypes = [ d.parent for d in frappe.get_all('DocField', {'fieldname': 'lft'}, ['parent']) ] add_home_page(bootinfo, doclist) bootinfo.page_info = get_allowed_pages() load_translations(bootinfo) add_timezone_info(bootinfo) load_conf_settings(bootinfo) load_print(bootinfo, doclist) doclist.extend(get_meta_bundle("Page")) bootinfo.home_folder = frappe.db.get_value("File", {"is_home_folder": 1}) bootinfo.navbar_settings = get_navbar_settings() bootinfo.notification_settings = get_notification_settings() # ipinfo if frappe.session.data.get('ipinfo'): bootinfo.ipinfo = frappe.session['data']['ipinfo'] # add docs bootinfo.docs = doclist for method in hooks.boot_session or []: frappe.get_attr(method)(bootinfo) if bootinfo.lang: bootinfo.lang = text_type(bootinfo.lang) bootinfo.versions = {k: v['version'] for k, v in get_versions().items()} bootinfo.error_report_email = frappe.conf.error_report_email bootinfo.calendars = sorted(frappe.get_hooks("calendars")) bootinfo.treeviews = frappe.get_hooks("treeviews") or [] bootinfo.lang_dict = get_lang_dict() bootinfo.success_action = get_success_action() bootinfo.update(get_email_accounts(user=frappe.session.user)) bootinfo.energy_points_enabled = is_energy_point_enabled() bootinfo.website_tracking_enabled = is_tracking_enabled() bootinfo.points = get_energy_points(frappe.session.user) bootinfo.frequently_visited_links = frequently_visited_links() bootinfo.link_preview_doctypes = get_link_preview_doctypes() bootinfo.additional_filters_config = get_additional_filters_from_hooks() bootinfo.desk_settings = get_desk_settings() bootinfo.app_logo_url = get_app_logo() return bootinfo
def get_bootinfo(): """build and return boot info""" frappe.set_user_lang(frappe.session.user) bootinfo = frappe._dict() hooks = frappe.get_hooks() doclist = [] # user get_user(bootinfo) # system info bootinfo["sysdefaults"] = frappe.defaults.get_defaults() bootinfo["server_date"] = frappe.utils.nowdate() if frappe.session["user"] != "Guest": bootinfo["user_info"] = get_fullnames() bootinfo["sid"] = frappe.session["sid"] # home page bootinfo.modules = {} for app in frappe.get_installed_apps(): try: bootinfo.modules.update(frappe.get_attr(app + ".config.desktop.get_data")() or {}) except ImportError: pass except AttributeError: pass bootinfo.module_app = frappe.local.module_app bootinfo.hidden_modules = frappe.db.get_global("hidden_modules") bootinfo.doctype_icons = dict( frappe.db.sql( """select name, icon from tabDocType where ifnull(icon,'')!=''""" ) ) bootinfo.doctype_icons.update( dict( frappe.db.sql( """select name, icon from tabPage where ifnull(icon,'')!=''""" ) ) ) add_home_page(bootinfo, doclist) add_allowed_pages(bootinfo) load_translations(bootinfo) add_timezone_info(bootinfo) load_conf_settings(bootinfo) load_print(bootinfo, doclist) # ipinfo if frappe.session["data"].get("ipinfo"): bootinfo["ipinfo"] = frappe.session["data"]["ipinfo"] # add docs bootinfo["docs"] = doclist for method in hooks.boot_session or []: frappe.get_attr(method)(bootinfo) if bootinfo.lang: bootinfo.lang = unicode(bootinfo.lang) bootinfo.error_report_email = frappe.get_hooks("error_report_email") return bootinfo
def load_translations(bootinfo): frappe.set_user_lang(frappe.session.user) if frappe.lang != 'en': bootinfo["__messages"] = frappe.get_lang_dict("include") bootinfo["lang"] = frappe.lang
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) #frappe.msgprint(data_import_doc.overwrite) if data_import_doc and isinstance(data_import_doc, string_types): data_import_doc = frappe.get_doc("Data Import", data_import_doc) #frappe.msgprint("found in database") #frappe.msgprint(data_import_doc.overwrite) 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 #frappe.msgprint("overwrite %s" % 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 #frappe.msgprint(doc) 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) #frappe.msgprint("%d" % len(rows)) #frappe.msgprint(rows) 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: frappe.msgprint("still overwrtie") 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 #frappe.msgprint("in batch %s" % overwrite) #frappe.msgprint("docName %s" % doc.get("name")) #frappe.msgprint("exist db %s" % frappe.db.exists(doctype,doc["name"])) row_idx = i + start_row doc = None publish_progress(i) #frappe.msgprint("in batch %s" % doc) 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"]) #frappe.msgprint("overwite %s" % original.name) original_name = original.name #frappe.msgprint(original) #frappe.msgprint(doc) original.update(doc) #frappe.msgprint(original) # preserve original name for case sensitivity original.name = original_name original.flags.ignore_links = ignore_links original.save() doc = original else: frappe.msgprint("not overwrite") 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_absolute_url(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_absolute_url(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_absolute_url(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_absolute_url(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_absolute_url("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
def work(): frappe.set_user(frappe.db.get_global('demo_accounts_user')) frappe.set_user_lang(frappe.db.get_global('demo_accounts_user')) if random.random() <= 0.6: report = "Ordered Items to be Billed" for so in list( set([ r[0] for r in query_report.run(report)["result"] if r[0] != "Total" ]))[:random.randint(1, 5)]: try: si = frappe.get_doc(make_sales_invoice(so)) si.set_posting_time = True si.posting_date = frappe.flags.current_date si.payment_schedule = [] for d in si.get("items"): if not d.income_account: d.income_account = "Sales - {}".format( frappe.get_cached_value('Company', si.company, 'abbr')) si.insert() si.submit() frappe.db.commit() except frappe.ValidationError: pass if random.random() <= 0.6: report = "Received Items to be Billed" for pr in list( set([ r[0] for r in query_report.run(report)["result"] if r[0] != "Total" ]))[:random.randint(1, 5)]: try: pi = frappe.get_doc(make_purchase_invoice(pr)) pi.set_posting_time = True pi.posting_date = frappe.flags.current_date pi.bill_no = random_string(6) pi.insert() pi.submit() frappe.db.commit() except frappe.ValidationError: pass if random.random() < 0.5: make_payment_entries("Sales Invoice", "Accounts Receivable") if random.random() < 0.5: make_payment_entries("Purchase Invoice", "Accounts Payable") if random.random() < 0.4: #make payment request against sales invoice sales_invoice_name = get_random("Sales Invoice", filters={"docstatus": 1}) if sales_invoice_name: si = frappe.get_doc("Sales Invoice", sales_invoice_name) if si.outstanding_amount > 0: payment_request = make_payment_request( dt="Sales Invoice", dn=si.name, recipient_id=si.contact_email, no_payment_link=1, submit_doc=True, mute_email=True, use_dummy_message=True) payment_entry = frappe.get_doc( make_payment_entry(payment_request.name)) payment_entry.posting_date = frappe.flags.current_date payment_entry.submit() make_pos_invoice()