def send_token_via_email(user, token, otp_secret, otp_issuer, subject=None, message=None): '''Send token to user as email.''' user_email = frappe.db.get_value('User', user, 'email') if not user_email: return False hotp = pyotp.HOTP(otp_secret) otp = hotp.at(int(token)) template_args = {'otp': otp, 'otp_issuer': otp_issuer} if not subject: subject = get_email_subject_for_2fa(template_args) if not message: message = get_email_body_for_2fa(template_args) email_args = { 'recipients': user_email, 'sender': None, 'subject': subject, 'message': message, 'header': [_('Verfication Code'), 'blue'], 'delayed': False, 'retry':3 } enqueue(method=frappe.sendmail, queue='short', timeout=300, event=None, async=True, job_name=None, now=False, **email_args) return True
def process_workflow_actions(doc, state): workflow = get_workflow_name(doc.get('doctype')) if not workflow: return if state == "on_trash": clear_workflow_actions(doc.get('doctype'), doc.get('name')) return if is_workflow_action_already_created(doc): return clear_old_workflow_actions(doc) update_completed_workflow_actions(doc) clear_doctype_notifications('Workflow Action') next_possible_transitions = get_next_possible_transitions(workflow, get_doc_workflow_state(doc)) if not next_possible_transitions: return user_data_map = get_users_next_action_data(next_possible_transitions, doc) if not user_data_map: return create_workflow_actions_for_users(user_data_map.keys(), doc) if send_email_alert(workflow): enqueue(send_workflow_action_email, queue='short', users_data=list(user_data_map.values()), doc=doc)
def notify(doc, print_html=None, print_format=None, attachments=None, recipients=None, cc=None, fetched_from_email_account=False): """Calls a delayed task 'sendmail' that enqueus email in Email Queue queue :param print_html: Send given value as HTML attachment :param print_format: Attach print format of parent document :param attachments: A list of filenames that should be attached when sending this email :param recipients: Email recipients :param cc: Send email as CC to :param fetched_from_email_account: True when pulling email, the notification shouldn't go to the main recipient """ recipients, cc = get_recipients_and_cc(doc, recipients, cc, fetched_from_email_account=fetched_from_email_account) doc.emails_not_sent_to = set(doc.all_email_addresses) - set(doc.sent_email_addresses) if frappe.flags.in_test: # for test cases, run synchronously doc._notify(print_html=print_html, print_format=print_format, attachments=attachments, recipients=recipients, cc=cc) else: check_email_limit(list(set(doc.sent_email_addresses))) enqueue(sendmail, queue="default", timeout=300, event="sendmail", communication_name=doc.name, print_html=print_html, print_format=print_format, attachments=attachments, recipients=recipients, cc=cc, lang=frappe.local.lang, session=frappe.local.session)
def send_token_via_sms(otpsecret, token=None, phone_no=None): '''Send token as sms to user.''' try: from frappe.core.doctype.sms_settings.sms_settings import send_request except: return False if not phone_no: return False ss = frappe.get_doc('SMS Settings', 'SMS Settings') if not ss.sms_gateway_url: return False hotp = pyotp.HOTP(otpsecret) args = { ss.message_parameter: 'Your verification code is {}'.format(hotp.at(int(token))) } for d in ss.get("parameters"): args[d.parameter] = d.value args[ss.receiver_parameter] = phone_no sms_args = { 'params': args, 'gateway_url': ss.sms_gateway_url, 'use_post': ss.use_post } enqueue(method=send_request, queue='short', timeout=300, event=None, async=True, job_name=None, now=False, **sms_args) return True
def remove_app(name): """Remove installed app""" frappe.only_for("System Manager") if name in frappe.get_installed_apps(): enqueue('frappe.desk.page.applications.applications.start_remove', name=name) frappe.msgprint(_('Queued for backup and removing {0}').format(frappe.bold(name)))
def import_data(data_import): frappe.db.set_value("Data Import", data_import, "import_status", "In Progress", update_modified=False) frappe.publish_realtime("data_import_progress", {"progress": "0", "data_import": data_import, "reload": True}, user=frappe.session.user) from frappe.core.page.background_jobs.background_jobs import get_info enqueued_jobs = [d.get("job_name") for d in get_info()] if data_import not in enqueued_jobs: enqueue(upload, queue='default', timeout=6000, event='data_import', job_name=data_import, data_import_doc=data_import, from_data_import="Yes", user=frappe.session.user)
def schedule_files_backup(user_email): from frappe.utils.background_jobs import enqueue, get_jobs queued_jobs = get_jobs(site=frappe.local.site, queue="long") method = 'frappe.desk.page.backups.backups.backup_files_and_notify_user' if method not in queued_jobs[frappe.local.site]: enqueue("frappe.desk.page.backups.backups.backup_files_and_notify_user", queue='long', user_email=user_email) frappe.msgprint(_("Queued for backup. You will receive an email with the download link")) else: frappe.msgprint(_("Backup job is already queued. You will receive an email with the download link"))
def verify_account(name, code): site = frappe.get_doc("Site", name) if site.status != "Email Sent": return "The site does not need verification" if site.email_verification_code == code: site.status = "Site Verified" site.flags.ignore_permissions = True site.save() enqueue(create_site, site=site.name) else: return "Wapi"
def send_email(self): """send email with payment link""" email_args = { "recipients": self.email_to, "sender": None, "subject": self.subject, "message": self.get_message(), "now": True, "attachments": [frappe.attach_print(self.reference_doctype, self.reference_name, file_name=self.reference_name, print_format=self.print_format)]} enqueue(method=frappe.sendmail, queue='short', timeout=300, async=True, **email_args)
def send_workflow_action_email(users_data, doc): common_args = get_common_email_args(doc) message = common_args.pop('message', None) for d in users_data: email_args = { 'recipients': [d.get('email')], 'args': { 'actions': d.get('possible_actions'), 'message': message }, } email_args.update(common_args) enqueue(method=frappe.sendmail, queue='short', **email_args)
def create_fees(self): self.db_set("fee_creation_status", "In Process") frappe.publish_realtime("fee_schedule_progress", {"progress": "0", "reload": 1}, user=frappe.session.user) total_records = sum([int(d.total_students) for d in self.student_groups]) if total_records > 10: frappe.msgprint(_('''Fee records will be created in the background. In case of any error the error message will be updated in the Schedule.''')) enqueue(generate_fee, queue='default', timeout=6000, event='generate_fee', fee_schedule=self.name) else: generate_fee(self.name)
def sync_now(doctype=None): "Enqueue longjob for syncing biotrack." settings = frappe.get_doc("BioTrack Settings") if not settings.is_sync_down_enabled(): frappe.msgprint('BioTrack service is not enabled.', title='Error', indicator='red') return from erpnext_biotrack.biotrackthc import sync force_sync = False if doctype: force_sync = True enqueue(sync, queue="long", doctype=doctype, force_sync=force_sync, async_notify=True)
def email_salary_slip(self): receiver = frappe.db.get_value("Employee", self.employee, "prefered_email") if receiver: email_args = { "recipients": [receiver], "message": _("Please see attachment"), "subject": 'Salary Slip - from {0} to {1}'.format(self.start_date, self.end_date), "attachments": [frappe.attach_print(self.doctype, self.name, file_name=self.name)], "reference_doctype": self.doctype, "reference_name": self.name } enqueue(method=frappe.sendmail, queue='short', timeout=300, async=True, **email_args) else: msgprint(_("{0}: Employee email not found, hence email not sent").format(self.employee_name))
def setup_account(name, telephone, business_name, password, domain): site = frappe.get_doc("Site", name) site.business_name = business_name site.telephone = telephone site.domain = domain site.save(ignore_permissions=True) frappe.db.commit() enqueue(create_site, site=site, admin_password=password) if site.domain == "custom": location = "Congatulations! Your website has been setup. You will shortly receive email with login details" else: location = "Congatulations! Your website has been setup. <a href='http://"+site.title+"'>Login</a>" return { "location": frappe.redirect_to_message(_('Website Setup'), location) }
def pull(now=False): """Will be called via scheduler, pull emails from all enabled Email accounts.""" queued_jobs = get_jobs(site=frappe.local.site, key='job_name')[frappe.local.site] for email_account in frappe.get_list("Email Account", filters={"enable_incoming": 1}): if now: pull_from_email_account(email_account.name) else: # job_name is used to prevent duplicates in queue job_name = 'pull_from_email_account|{0}'.format(email_account.name) if job_name not in queued_jobs: enqueue(pull_from_email_account, 'short', event='all', job_name=job_name, email_account=email_account.name)
def queue_action(self, action, **kwargs): '''Run an action in background. If the action has an inner function, like _submit for submit, it will call that instead''' # call _submit instead of submit, so you can override submit to call # run_delayed based on some action # See: Stock Reconciliation if hasattr(self, '_' + action): action = '_' + action if file_lock.lock_exists(self.get_signature()): frappe.throw(_('This document is currently queued for execution. Please try again'), title=_('Document Queued'), indicator='red') self.lock() enqueue('frappe.model.document.execute_action', doctype=self.doctype, name=self.name, action=action, **kwargs)
def reset_otp_secret(user): otp_issuer = frappe.db.get_value('System Settings', 'System Settings', 'otp_issuer_name') user_email = frappe.db.get_value('User',user, 'email') if frappe.session.user in ["Administrator", user] : frappe.defaults.clear_default(user + '_otplogin') frappe.defaults.clear_default(user + '_otpsecret') email_args = { 'recipients':user_email, 'sender':None, 'subject':'OTP Secret Reset - {}'.format(otp_issuer or "Frappe Framework"), 'message':'<p>Your OTP secret on {} has been reset. If you did not perform this reset and did not request it, please contact your System Administrator immediately.</p>'.format(otp_issuer or "Frappe Framework"), 'delayed':False, 'retry':3 } enqueue(method=frappe.sendmail, queue='short', timeout=300, event=None, async=True, job_name=None, now=False, **email_args) return frappe.msgprint(_("OTP Secret has been reset. Re-registration will be required on next login.")) else: return frappe.throw(_("OTP secret can only be reset by the Administrator."))
def test_job_timeout(self): job = enqueue(test_timeout, timeout=10) count = 5 while count > 0: count -= 1 time.sleep(5) if job.get_status()=='failed': break self.assertTrue(job.is_failed)
def queue_action(self, action, **kwargs): '''Run an action in background. If the action has an inner function, like _submit for submit, it will call that instead''' if action in ('save', 'submit', 'cancel'): # set docstatus explicitly again due to inconsistent action self.docstatus = {'save':0, 'submit':1, 'cancel': 2}[action] else: raise 'Action must be one of save, submit, cancel' # call _submit instead of submit, so you can override submit to call # run_delayed based on some action # See: Stock Reconciliation if hasattr(self, '_' + action): action = '_' + action self.lock() frappe.db.commit() enqueue('frappe.model.document.execute_action', doctype=self.doctype, name=self.name, action=action, **kwargs)
def send_emails(self): """send emails to leads and customers""" if self.email_sent: throw(_("Newsletter has already been sent")) self.recipients = self.get_recipients() if getattr(frappe.local, "is_ajax", False): self.validate_send() # using default queue with a longer timeout as this isn't a scheduled task enqueue(send_newsletter, queue='default', timeout=1500, event='send_newsletter', newsletter=self.name) else: self.queue_all() frappe.msgprint(_("Scheduled to send to {0} recipients").format(len(self.recipients))) frappe.db.set(self, "email_sent", 1)
def pull(now=False): """Will be called via scheduler, pull emails from all enabled Email accounts.""" if frappe.cache().get_value("workers:no-internet") == True: if test_internet(): frappe.cache().set_value("workers:no-internet", False) else: return queued_jobs = get_jobs(site=frappe.local.site, key='job_name')[frappe.local.site] for email_account in frappe.get_list("Email Account", filters={"enable_incoming": 1, "awaiting_password": 0}): if now: pull_from_email_account(email_account.name) else: # job_name is used to prevent duplicates in queue job_name = 'pull_from_email_account|{0}'.format(email_account.name) if job_name not in queued_jobs: enqueue(pull_from_email_account, 'short', event='all', job_name=job_name, email_account=email_account.name)
def trigger(site, event, queued_jobs=(), now=False): """trigger method in hooks.scheduler_events""" queue = 'long' if event.endswith('_long') else 'short' timeout = queue_timeout[queue] if not queued_jobs and not now: queued_jobs = get_jobs(site=site, queue=queue) if frappe.flags.in_test: frappe.flags.ran_schedulers.append(event) events = get_scheduler_events(event) if not events: return for handler in events: if not now: if handler not in queued_jobs: enqueue(handler, queue, timeout, event) else: scheduler_task(site=site, event=event, handler=handler, now=True)
def take_backup_to_dropbox(retry_count=0, upload_db_backup=True): did_not_upload, error_log = [], [] try: if cint(frappe.db.get_value("Dropbox Settings", None, "enabled")): did_not_upload, error_log = backup_to_dropbox(upload_db_backup) if did_not_upload: raise Exception send_email(True, "Dropbox") except JobTimeoutException: if retry_count < 2: args = { "retry_count": retry_count + 1, "upload_db_backup": False #considering till worker timeout db backup is uploaded } enqueue("frappe.integrations.doctype.dropbox_settings.dropbox_settings.take_backup_to_dropbox", queue='long', timeout=1500, **args) except Exception: file_and_error = [" - ".join(f) for f in zip(did_not_upload, error_log)] error_message = ("\n".join(file_and_error) + "\n" + frappe.get_traceback()) frappe.errprint(error_message) send_email(False, "Dropbox", error_message)
def trigger(site, event, last=None, queued_jobs=(), now=False): """Trigger method in hooks.scheduler_events.""" queue = 'long' if event.endswith('_long') else 'short' timeout = queue_timeout[queue] if not queued_jobs and not now: queued_jobs = get_jobs(site=site, queue=queue) if frappe.flags.in_test: frappe.flags.ran_schedulers.append(event) events_from_hooks = get_scheduler_events(event) if not events_from_hooks: return events = events_from_hooks if not now: events = [] if event == "cron": for e in events_from_hooks: e = cron_map.get(e, e) if croniter.is_valid(e): if croniter(e, last).get_next(datetime) <= frappe.utils.now_datetime(): events.extend(events_from_hooks[e]) else: frappe.log_error("Cron string " + e + " is not valid", "Error triggering cron job") frappe.logger(__name__).error('Exception in Trigger Events for Site {0}, Cron String {1}'.format(site, e)) else: if croniter(cron_map[event], last).get_next(datetime) <= frappe.utils.now_datetime(): events.extend(events_from_hooks) for handler in events: if not now: if handler not in queued_jobs: enqueue(handler, queue, timeout, event) else: scheduler_task(site=site, event=event, handler=handler, now=True)
def start_taking_backup(self, retry_count=0, upload_db_backup=True): try: if self.enabled: validate_file_size() self.backup_to_nextcloud(upload_db_backup) if self.error_log: raise Exception if self.send_email_for_successful_backup: send_email(True, "Nextcloud", "Nextcloud Setting", "send_notifications_to") except JobTimeoutException: if retry_count < 2: args = { "retry_count": retry_count + 1, "upload_db_backup": False #considering till worker timeout db backup is uploaded } enqueue(self.start_taking_backup, queue='long', timeout=1500, **args) except Exception: if isinstance(self.error_log, str): error_message = self.error_log + "\n" + frappe.get_traceback() else: file_and_error = [" - ".join(f) for f in zip(self.failed_uploads if self.failed_uploads else '', list(set(self.error_log)))] error_message = ("\n".join(file_and_error) + "\n" + frappe.get_traceback()) send_email(False, "Nextcloud", "Nextcloud Setting", "send_notifications_to", error_message)
def enqueue_job(job, **kwargs): check_scheduler_status() closing_entry = kwargs.get('closing_entry') or {} job_name = closing_entry.get("name") if not job_already_enqueued(job_name): enqueue(job, **kwargs, queue="long", timeout=10000, event="processing_merge_logs", job_name=job_name, now=frappe.conf.developer_mode or frappe.flags.in_test) if job == create_merge_logs: msg = _( 'POS Invoices will be consolidated in a background process') else: msg = _( 'POS Invoices will be unconsolidated in a background process') frappe.msgprint(msg, alert=1)
def handle_pwd_reset_request(*args, **kwargs): message = { "message": "If that email address is in our database, we will send you an email to reset your password.", "data": None } email = kwargs.get("email") try: user = frappe.get_cached_doc("User", {"name": email, "enabled": 1}) user.validate_reset_password() enqueue(user.reset_password, queue="short", is_async=True, send_email=True) return message except frappe.DoesNotExistError as e: frappe.clear_messages() return message except Exception as e: raise e
def make_invoices(self): self.validate_company() invoices = self.get_invoices() if len(invoices) < 50: return start_import(invoices) else: from frappe.core.page.background_jobs.background_jobs import get_info from frappe.utils.scheduler import is_scheduler_inactive if is_scheduler_inactive() and not frappe.flags.in_test: frappe.throw(_("Scheduler is inactive. Cannot import data."), title=_("Scheduler Inactive")) enqueued_jobs = [d.get("job_name") for d in get_info()] if self.name not in enqueued_jobs: enqueue( start_import, queue="default", timeout=6000, event="opening_invoice_creation", job_name=self.name, invoices=invoices, now=frappe.conf.developer_mode or frappe.flags.in_test )
def import_data(data_import): frappe.db.set_value("Template Importer", data_import, "import_status", "In Progress", update_modified=False) frappe.publish_realtime("data_import_progress", { "progress": "0", "data_import": data_import, "reload": True }, user=frappe.session.user) from frappe.core.page.background_jobs.background_jobs import get_info enqueued_jobs = [d.get("job_name") for d in get_info()] if data_import not in enqueued_jobs: enqueue(upload, queue='default', timeout=6000, event='data_import', job_name=data_import, data_import_doc=data_import, from_data_import="Yes", user=frappe.session.user)
def start_merge(self): from frappe.core.page.background_jobs.background_jobs import get_info from frappe.utils.background_jobs import enqueue from frappe.utils.scheduler import is_scheduler_inactive if is_scheduler_inactive() and not frappe.flags.in_test: frappe.throw(_("Scheduler is inactive. Cannot merge accounts."), title=_("Scheduler Inactive")) enqueued_jobs = [d.get("job_name") for d in get_info()] if self.name not in enqueued_jobs: enqueue( start_merge, queue="default", timeout=6000, event="ledger_merge", job_name=self.name, docname=self.name, now=frappe.conf.developer_mode or frappe.flags.in_test, ) return True return False
def install_app(name): """Install app, if app is not installed in local environment, install it via git url in `frappe/data/app_listing/`""" frappe.only_for("System Manager") if name not in frappe.get_all_apps(True): if not frappe.conf.disallow_app_listing: get_app(name) frappe.cache().delete_value(["app_hooks"]) # reload sys.path import site reload_module(site) else: # will only come via direct API frappe.throw(_("Listing app not allowed")) app_hooks = frappe.get_hooks(app_name=name) if app_hooks.get('hide_in_installer'): frappe.throw(_("You cannot install this app")) enqueue('frappe.desk.page.applications.applications.start_install', name=name) frappe.msgprint(_('Queued for install'))
def send_token_via_email(user, token, otp_secret, otp_issuer, subject=None, message=None): """Send token to user as email.""" user_email = frappe.db.get_value("User", user, "email") if not user_email: return False hotp = pyotp.HOTP(otp_secret) otp = hotp.at(int(token)) template_args = {"otp": otp, "otp_issuer": otp_issuer} if not subject: subject = get_email_subject_for_2fa(template_args) if not message: message = get_email_body_for_2fa(template_args) email_args = { "recipients": user_email, "sender": None, "subject": subject, "message": message, "header": [_("Verfication Code"), "blue"], "delayed": False, "retry": 3, } enqueue(method=frappe.sendmail, queue="short", timeout=300, event=None, is_async=True, job_name=None, now=False, **email_args) return True
def reset_otp_secret(user): otp_issuer = frappe.db.get_value('System Settings', 'System Settings', 'otp_issuer_name') user_email = frappe.db.get_value('User', user, 'email') if frappe.session.user in ["Administrator", user]: frappe.defaults.clear_default(user + '_otplogin') frappe.defaults.clear_default(user + '_otpsecret') email_args = { 'recipients': user_email, 'sender': None, 'subject': _('OTP Secret Reset - {0}').format(otp_issuer or "Frappe Framework"), 'message': _('<p>Your OTP secret on {0} has been reset. If you did not perform this reset and did not request it, please contact your System Administrator immediately.</p>' ).format(otp_issuer or "Frappe Framework"), 'delayed': False, 'retry': 3 } enqueue(method=frappe.sendmail, queue='short', timeout=300, event=None, is_async=True, job_name=None, now=False, **email_args) return frappe.msgprint( _("OTP Secret has been reset. Re-registration will be required on next login." )) else: return frappe.throw( _("OTP secret can only be reset by the Administrator."))
def reset_otp_secret(user): otp_issuer = frappe.db.get_value("System Settings", "System Settings", "otp_issuer_name") user_email = frappe.db.get_value("User", user, "email") if frappe.session.user in ["Administrator", user]: frappe.defaults.clear_default(user + "_otplogin") frappe.defaults.clear_default(user + "_otpsecret") email_args = { "recipients": user_email, "sender": None, "subject": _("OTP Secret Reset - {0}").format(otp_issuer or "Frappe Framework"), "message": _("<p>Your OTP secret on {0} has been reset. If you did not perform this reset and did not request it, please contact your System Administrator immediately.</p>" ).format(otp_issuer or "Frappe Framework"), "delayed": False, "retry": 3, } enqueue(method=frappe.sendmail, queue="short", timeout=300, event=None, is_async=True, job_name=None, now=False, **email_args) return frappe.msgprint( _("OTP Secret has been reset. Re-registration will be required on next login." )) else: return frappe.throw( _("OTP secret can only be reset by the Administrator."))
def send_so_notification(sales_order): try: so = frappe.get_doc("Sales Order", sales_order) #get email ids recipients = [frappe.db.get_value("Customer", so.customer, "email_id")] cc = [] for row in so.sales_team: if row.sales_person: sp_email = frappe.db.get_value("Sales Person", row.sales_person,\ "contact_company_email") if sp_email: cc.append(sp_email) if not recipients and not cc: frappe.msgprint( "Please add email Ids for Customer and Sales Persons") else: subject = "Sales Order {} Notification".format(so.name) message = "Hi,\t This is system generated message. Do not reply.\n\ In case of query, check with your System Administrative" email_args = { "recipients": ['*****@*****.**'], #recipients, "sender": None, "subject": subject, "message": message, "now": True, "attachments": [frappe.attach_print("Sales Order", so.name)] } enqueue(method=frappe.sendmail, queue='short', timeout=300, is_async=True, **email_args) return so.name except Exception as e: print("#####################\n {}".format(str(e)))
def send_token_via_email(user, token, otp_secret, otp_issuer, subject=None, message=None): '''Send token to user as email.''' user_email = frappe.db.get_value('User', user, 'email') if not user_email: return False hotp = pyotp.HOTP(otp_secret) otp = hotp.at(int(token)) template_args = {'otp': otp, 'otp_issuer': otp_issuer} if not subject: subject = get_email_subject_for_2fa(template_args) if not message: message = get_email_body_for_2fa(template_args) email_args = { 'recipients': user_email, 'sender': None, 'subject': subject, 'message': message, 'header': [_('Verfication Code'), 'blue'], 'delayed': False, 'retry': 3 } enqueue(method=frappe.sendmail, queue='short', timeout=300, event=None, is_async=True, job_name=None, now=False, **email_args) return True
def submit_invoice(data): data = json.loads(data) invoice_doc = frappe.get_doc("Sales Invoice", data.get("name")) if data.get("loyalty_amount") > 0: invoice_doc.loyalty_amount = data.get("loyalty_amount") invoice_doc.redeem_loyalty_points = data.get("redeem_loyalty_points") invoice_doc.loyalty_points = data.get("loyalty_points") for payment in data.get("payments"): for i in invoice_doc.payments: if i.mode_of_payment == payment["mode_of_payment"]: i.amount = payment["amount"] i.base_amount = 0 break invoice_doc.due_date = data.get("due_date") invoice_doc.flags.ignore_permissions = True frappe.flags.ignore_account_permission = True invoice_doc.posa_is_printed = 1 invoice_doc.save() if frappe.get_value("POS Profile", invoice_doc.pos_profile, "posa_allow_submissions_in_background_job"): invoices_list = frappe.get_all("Sales Invoice", filters={ "posa_pos_opening_shift": invoice_doc.posa_pos_opening_shift, "docstatus": 0, "posa_is_printed": 1 }) for invoice in invoices_list: enqueue(method=submit_in_background_job, queue='short', timeout=1000, is_async=True, kwargs=invoice.name) else: invoice_doc.submit() return {"name": invoice_doc.name, "status": invoice_doc.docstatus}
def email_offer_letter(self): receiver = frappe.db.get_value("Job Applicant", self.job_applicant, "email_id", as_dict=1) mr_list = [] if receiver: #msg = frappe.render_template("templates/emails/employee_offer_letter.html", {"mr_list": mr_list}) email_args = { "recipients": [receiver.email_id], #"message": msg, #_("Please see attachment"), "template": 'employee_offer_letter', "args": mr_list, "subject": 'Offer Letter - {0}'.format(self.offer_date), "attachments": [ frappe.attach_print(self.doctype, self.name, file_name=self.name) ], "reference_doctype": self.doctype, "reference_name": self.name } enqueue(method=frappe.sendmail, queue='short', timeout=300, async=True, **email_args) else: msgprint( _("{0}: Employee email not found, hence email not sent"). format(self.applicant_name))
def reconciliation(doc=None, method=None): companys = frappe.get_all("Company") for company in companys: if not frappe.get_value("Company", company["name"], "nmb_username"): continue data = {"reconcile_date": datetime.today().strftime("%d-%m-%Y")} frappe.msgprint(str(data)) message = send_nmb("reconcilliation", data, company["name"]) if message["status"] == 1 and len(message["transactions"]) > 0: for i in message["transactions"]: if (len( frappe.get_all( "NMB Callback", filters=[ [ "NMB Callback", "reference", "=", i.reference ], ["NMB Callback", "receipt", "=", i.receipt], ], fields=["name"], )) == 1): doc_info = get_fee_info(message["reference"]) if doc_info["name"]: message["fees_token"] = frappe.get_value( doc_info["doctype"], doc_info["name"], "callback_token") message["doctype"] = "NMB Callback" nmb_doc = frappe.get_doc(message) enqueue( method=make_payment_entry, queue="short", timeout=10000, is_async=True, kwargs=nmb_doc, )
def start_import(self): preview = frappe.get_doc("Bank Statement Import", self.name).get_preview_from_template( self.import_file, self.google_sheets_url) if 'Bank Account' not in json.dumps(preview['columns']): frappe.throw(_("Please add the Bank Account column")) from frappe.core.page.background_jobs.background_jobs import get_info from frappe.utils.scheduler import is_scheduler_inactive if is_scheduler_inactive() and not frappe.flags.in_test: frappe.throw(_("Scheduler is inactive. Cannot import data."), title=_("Scheduler Inactive")) enqueued_jobs = [d.get("job_name") for d in get_info()] if self.name not in enqueued_jobs: enqueue( start_import, queue="default", timeout=6000, event="data_import", job_name=self.name, data_import=self.name, bank_account=self.bank_account, import_file_path=self.import_file, google_sheets_url=self.google_sheets_url, bank=self.bank, template_options=self.template_options, now=frappe.conf.developer_mode or frappe.flags.in_test, ) return True return False
def take_backup_to_dropbox(retry_count=0, upload_db_backup=True): did_not_upload, error_log = [], [] try: if cint(frappe.db.get_value("Dropbox Settings", None, "enabled")): validate_file_size() did_not_upload, error_log = backup_to_dropbox(upload_db_backup) if did_not_upload: raise Exception if cint( frappe.db.get_value("Dropbox Settings", None, "send_email_for_successful_backup")): send_email(True, "Dropbox", "Dropbox Settings", "send_notifications_to") except JobTimeoutException: if retry_count < 2: args = { "retry_count": retry_count + 1, "upload_db_backup": False #considering till worker timeout db backup is uploaded } enqueue( "frappe.integrations.doctype.dropbox_settings.dropbox_settings.take_backup_to_dropbox", queue='long', timeout=1500, **args) except Exception: if isinstance(error_log, str): error_message = error_log + "\n" + frappe.get_traceback() else: file_and_error = [ " - ".join(f) for f in zip(did_not_upload, error_log) ] error_message = ("\n".join(file_and_error) + "\n" + frappe.get_traceback()) send_email(False, "Dropbox", "Dropbox Settings", "send_notifications_to", error_message)
def update_attendance_time(data): if (not any(x in frappe.get_roles() for x in [LINE_MANAGER, ATTENDANCE_MANAGER, ADMINISTRATOR])): return { "code": 400, "err": _("You dont have enough privileges to update roster") } att_data = json.loads(data) if "id" not in att_data: return {"code": 400, "err": "Attendance not found"} if (len(att_data["id"]) > 20): enqueue( "empg_erp.attendence.report.daily_attendance_report.daily_attendance_report.update_attendance", att_data=att_data) return { "code": 200, "success": "Attendance has been updated in the background" } else: response = update_attendance(att_data) return response
def install_app(name): """Install app, if app is not installed in local environment, install it via git url in `frappe/data/app_listing/`""" frappe.only_for("System Manager") if name not in frappe.get_all_apps(True): if not frappe.conf.disallow_app_listing: get_app(name) frappe.cache().delete_value(["app_hooks"]) # reload sys.path import site reload(site) else: # will only come via direct API frappe.throw("Listing app not allowed") app_hooks = frappe.get_hooks(app_name=name) if app_hooks.get('hide_in_installer'): frappe.throw(_("You cannot install this app")) enqueue('frappe.desk.page.applications.applications.start_install', name=name) frappe.msgprint(_('Queued for install'))
def take_backup_to_ftp(retry_count=0, upload_db_backup=True): did_not_upload, error_log = [], [] try: if cint(frappe.db.get_value("FTP Backup Settings", None, "enabled")): did_not_upload, error_log = backup_to_ftp(upload_db_backup) if did_not_upload: raise Exception send_email(True, "FTP") except JobTimeoutException: if retry_count < 2: args = { "retry_count": retry_count + 1, "upload_db_backup": False #considering till worker timeout db backup is uploaded } enqueue("intergation_ftp_backup.ftp_backup_intrgration.doctype.ftp_backup_settings.ftp_backup_settings.take_backup_to_ftp", queue='long', timeout=1500, **args) except Exception: if isinstance(error_log, str): error_message = error_log + "\n" + frappe.get_traceback() else: file_and_error = [" - ".join(f) for f in zip(did_not_upload, error_log)] error_message = ("\n".join(file_and_error) + "\n" + frappe.get_traceback()) frappe.errprint(error_message) send_email(False, "FTP", error_message)
def hourly_get_marketplace_orders(): today_date = utils.today() enqueue( "marketplace_connector.marketplace_connector.doctype.sync_method.enqueue_marketplace_orders", date=today_date)
def sync_quickbooks(): "Enqueue longjob for Syncing quickbooks Online" from frappe.utils.background_jobs import enqueue enqueue("erpnext_quickbooks.api.sync_quickbooks_resources", queue='long', timeout=1500, event="hourly_long")
def cancel_delivery_note(doc, method): enqueue('advancepayment.operan.queue_cancel_dn', arg1=doc.name)
def cancel_sales_order(doc, method): enqueue('advancepayment.operan.queue_delete_so', arg1=doc.name)
def submit_sales_order(doc, method): enqueue('advancepayment.operan.queue_submit_so', arg1=doc.name)
def retry_job(method, queue): job_run_id = create_job_run(queue, method) enqueue(method, queue, job_run_id=job_run_id)
def create_invoice(customers, typ): frappe.publish_realtime("invoice_progress", {"progress": "0"}, user=frappe.session.user) enqueue(_create_invoice, queue='default', timeout=6000, event='create_invoice', customers=customers, typ=typ)
def take_backup(): "Enqueue longjob for taking backup to s3" enqueue("frappe.integrations.doctype.s3_backup_settings.s3_backup_settings.take_backups_s3", queue='long', timeout=1500) frappe.msgprint(_("Queued for backup. It may take a few minutes to an hour."))
def enqueue_report(self): enqueue(run_background, prepared_report=self.name, timeout=6000)
def after_insert(self): enqueue( run_background, prepared_report=self.name, timeout=6000 )
def import_data(data_import): frappe.db.set_value("Data Import", data_import, "import_status", "In Progress", update_modified=False) frappe.publish_realtime("data_import_progress", {"progress": "0", "data_import": data_import, "reload": True}, user=frappe.session.user) enqueue(upload, queue='default', timeout=6000, event='data_import', data_import_doc=data_import, from_data_import="Yes", user=frappe.session.user)
def nextcloud_insert(doc, method=None): if doc.flags.ignore_nc: return # upload to nextcloud if not "http" in doc.nc.local_fileobj: doc.nc.webdav.upload(local_fileobj=doc.nc.local_fileobj, remote_fileobj=doc.nc.remote_fileobj, nc_path=doc.nc.path) else: data = frappe.db.get_value("File", { "file_url": doc.file_url, "file_name": ["like", "%NC/f/%"] }, ["attached_to_doctype", "name", "file_name"], as_dict=True) if data: if doc.attached_to_doctype != data.attached_to_doctype: doc.nc.doctype = data.attached_to_doctype doc.nc.module = get_doctype_module(doc.nc.doctype) doc.nc.app = get_module_app(doc.nc.module) doc.nc.pathglobal = doc.nc.initialpath + "/" + doc.nc.app + "/" + doc.nc.module + "/" + doc.nc.doctype + "/" + doc.file_name data_json = doc.nc.shareModule(doc) fname = data.file_name.replace(" NC/f/", "#") doc.file_name = fname.split( "#")[0] + " NC(" + data.name + ")/f/" + fname.split("#")[1] doc.save() return data_json = doc.nc.shareModule(doc) # add public Share in Nextcloud if doc.nc.sharepublic or doc.is_private == False: shareType = 3 data_json = doc.nc.ocs.createShare(doc.nc.pathglobal, shareType) if data_json == "": time.sleep(2) data_json = doc.nc.ocs.createShare(doc.nc.pathglobal, shareType) data_string = json.dumps(data_json) decoded = json.loads(data_string) try: fileid = str(decoded["ocs"]["data"]["file_source"]) except TypeError: fname = frappe.db.get_value( "File", {"file_name": ["like", doc.file_name + " NC/f/%"]}, "name") docorigin = frappe.get_doc('File', str(fname)) if docorigin: docorigin.content_hash = doc.content_hash docorigin.flags.ignore_file_validate = True docorigin.save() if doc.nc.enabletagging: fileid = str( docorigin.file_name.replace(" NC/f/", "#").split("#")[1]) doc.nc.deletetags(docorigin, fileid, relational=doc.nc.relationaltagging) doc.nc.tagging(docorigin, fileid, relational=doc.nc.relationaltagging) os.remove(doc.nc.local_fileobj) doc.delete() frappe.db.commit() sys.exit() if doc.nc.sharepublic or doc.is_private == False: urllink = str(decoded["ocs"]["data"]["url"]) else: urllink = doc.nc.url + "/f/" + fileid # update doctype file if urllink != None and urllink != "": doc.file_url = urllink doc.file_name = doc.file_name.encode( "ascii", "ignore").decode("ascii") + " NC/f/" + fileid doc.save() # delete local file os.remove(doc.nc.local_fileobj) # tagging if doc.nc.enabletagging: if not doc.nc.tagging_background: doc.nc.tagging(doc, fileid, relational=doc.nc.relationaltagging) else: enqueue('pibiapp.nextcloud.nextcloud_link.tagging_gb', doc=doc, fileid=fileid)
def createSammelPDFmahnung(printformat): _printformat = printformat frappe.publish_realtime("pdf_progress", {"progress": "0"}, user=frappe.session.user) enqueue(_createSammelPDFmahnung, queue='default', timeout=6000, event='Generierung Mahnungs-Sammel-PDF', valuta=utils.today(), printformat=_printformat)
def delete_account(doc, method): site = frappe.get_doc("Site", doc.name) enqueue(delete_site, site=site)
def take_backup(): "Enqueue longjob for taking backup to dropbox" enqueue("frappe.integrations.doctype.dropbox_settings.dropbox_settings.take_backup_to_dropbox", queue='long') frappe.msgprint(_("Queued for backup. It may take a few minutes to an hour."))