def get_transitions(doc, workflow = None): '''Return list of possible transitions for the given doc''' doc = frappe.get_doc(frappe.parse_json(doc)) if doc.is_new(): return [] frappe.has_permission(doc, 'read', throw=True) roles = frappe.get_roles() if not workflow: workflow = get_workflow(doc.doctype) current_state = doc.get(workflow.workflow_state_field) if not current_state: frappe.throw(_('Workflow State not set'), WorkflowStateError) transitions = [] for transition in workflow.transitions: if transition.state == current_state and transition.allowed in roles: if transition.condition: # if condition, evaluate # access to frappe.db.get_value and frappe.db.get_list success = frappe.safe_eval(transition.condition, dict(frappe = frappe._dict( db = frappe._dict(get_value = frappe.db.get_value, get_list=frappe.db.get_list), session = frappe.session )), dict(doc = doc)) if not success: continue transitions.append(transition.as_dict()) return transitions
def validate_condition(self): temp_doc = frappe.new_doc(self.document_type) if self.condition: try: frappe.safe_eval(self.condition, None, get_context(temp_doc)) except: frappe.throw(_("The condition '{0}' is invalid").format(self.condition))
def validate_formula(self): # evaluate the formula with 0's to make sure it is valid test_formula = self.formula.replace("\r", "").replace("\n", "") regex = r"\{(.*?)\}" mylist = re.finditer(regex, test_formula, re.MULTILINE | re.DOTALL) for dummy1, match in enumerate(mylist): for dummy2 in range(0, len(match.groups())): test_formula = test_formula.replace('{' + match.group(1) + '}', "0") try: frappe.safe_eval(test_formula, None, {'max':max, 'min': min}) except Exception: frappe.throw(_("Error evaluating the criteria formula"))
def set_breadcrumbs(self, context): """Build breadcrumbs template """ if self.breadcrumbs: context.parents = frappe.safe_eval(self.breadcrumbs, { "_": _ }) if not "no_breadcrumbs" in context: if "<!-- no-breadcrumbs -->" in context.main_section: context.no_breadcrumbs = 1
def calculate_weighted_score(self, weighing_function): try: weighed_score = frappe.safe_eval(self.get_eval_statement(weighing_function), None, {'max':max, 'min': min}) except Exception: frappe.throw(_("Could not solve weighted score function. Make sure the formula is valid."),frappe.ValidationError) weighed_score = 0 return weighed_score
def calculate_criteria(self): for crit in self.criteria: try: crit.score = min(crit.max_score, max( 0 ,frappe.safe_eval(self.get_eval_statement(crit.formula), None, {'max':max, 'min': min}))) except Exception: frappe.throw(_("Could not solve criteria score function for {0}. Make sure the formula is valid.".format(crit.criteria_name)),frappe.ValidationError) crit.score = 0
def set_status(self, update=False, status=None, update_modified=True): if self.is_new(): if self.get('amended_from'): self.status = 'Draft' return if self.doctype in status_map: _status = self.status if status and update: self.db_set("status", status) sl = status_map[self.doctype][:] sl.reverse() for s in sl: if not s[1]: self.status = s[0] break elif s[1].startswith("eval:"): if frappe.safe_eval(s[1][5:], None, { "self": self.as_dict(), "getdate": getdate, "nowdate": nowdate, "get_value": frappe.db.get_value }): self.status = s[0] break elif getattr(self, s[1])(): self.status = s[0] break if self.status != _status and self.status not in ("Cancelled", "Partially Ordered", "Ordered", "Issued", "Transferred"): self.add_comment("Label", _(self.status)) if update: self.db_set('status', self.status, update_modified = update_modified)
def calculate_criteria(self): #Get the criteria for crit in self.criteria: #me = "" my_eval_statement = crit.formula.replace("\r", "").replace("\n", "") #for let in my_eval_statement: # me += let.encode('hex') + " " #frappe.msgprint(me) for var in self.variables: if var.value: if var.param_name in my_eval_statement: my_eval_statement = my_eval_statement.replace('{' + var.param_name + '}', "{:.2f}".format(var.value)) else: if var.param_name in my_eval_statement: my_eval_statement = my_eval_statement.replace('{' + var.param_name + '}', '0.0') #frappe.msgprint(my_eval_statement ) my_eval_statement = my_eval_statement.replace('<','<').replace('>','>') try: crit.score = min(crit.max_score, max( 0 ,frappe.safe_eval(my_eval_statement, None, {'max':max, 'min': min}))) except Exception: frappe.throw(_("Could not solve criteria score function for {0}. Make sure the formula is valid.".format(crit.criteria_name)),frappe.ValidationError) crit.score = 0
def get_context(self, context): '''Build context to render the `web_form.html` template''' self.set_web_form_module() context._login_required = False if self.login_required and frappe.session.user == "Guest": context._login_required = True doc, delimeter = make_route_string(frappe.form_dict) context.doc = doc context.delimeter = delimeter # check permissions if frappe.session.user == "Guest" and frappe.form_dict.name: frappe.throw(_("You need to be logged in to access this {0}.").format(self.doc_type), frappe.PermissionError) if frappe.form_dict.name and not has_web_form_permission(self.doc_type, frappe.form_dict.name): frappe.throw(_("You don't have the permissions to access this document"), frappe.PermissionError) self.reset_field_parent() if self.is_standard: self.use_meta_fields() if not context._login_required: if self.allow_edit: if self.allow_multiple: if not frappe.form_dict.name and not frappe.form_dict.new: self.build_as_list(context) else: if frappe.session.user != 'Guest' and not frappe.form_dict.name: frappe.form_dict.name = frappe.db.get_value(self.doc_type, {"owner": frappe.session.user}, "name") if not frappe.form_dict.name: # only a single doc allowed and no existing doc, hence new frappe.form_dict.new = 1 # always render new form if login is not required or doesn't allow editing existing ones if not self.login_required or not self.allow_edit: frappe.form_dict.new = 1 self.load_document(context) context.parents = self.get_parents(context) if self.breadcrumbs: context.parents = frappe.safe_eval(self.breadcrumbs, { "_": _ }) context.has_header = ((frappe.form_dict.name or frappe.form_dict.new) and (frappe.session.user!="Guest" or not self.login_required)) if context.success_message: context.success_message = frappe.db.escape(context.success_message.replace("\n", "<br>")) self.add_custom_context_and_script(context) if not context.max_attachment_size: context.max_attachment_size = get_max_file_size() / 1024 / 1024
def get_value_from_fieldname(field_map, fieldname_field, doc): field_name = get_source_value(field_map, fieldname_field) if field_name.startswith('eval:'): value = frappe.safe_eval(field_name[5:], dict(frappe=frappe)) elif field_name[0] in ('"', "'"): value = field_name[1:-1] else: value = get_source_value(doc, field_name) return value
def eval_tax_slab_condition(self, condition, data): try: condition = condition.strip() if condition: return frappe.safe_eval(condition, self.whitelisted_globals, data) except NameError as err: frappe.throw(_("Name error: {0}".format(err))) except SyntaxError as err: frappe.throw(_("Syntax error in condition: {0}".format(err))) except Exception as e: frappe.throw(_("Error in formula or condition: {0}".format(e))) raise
def eval_condition_and_formula(self, d, data): try: if d.condition: if not frappe.safe_eval(d.condition, None, data): return None amount = d.amount if d.amount_based_on_formula: if d.formula: amount = frappe.safe_eval(d.formula, None, data) if amount: data[d.abbr] = amount return amount except NameError as err: frappe.throw(_("Name error: {0}".format(err))) except SyntaxError as err: frappe.throw(_("Syntax error in formula or condition: {0}".format(err))) except Exception, e: frappe.throw(_("Error in formula or condition: {0}".format(e))) raise
def get_feedback_request_details(reference_doctype, reference_name, trigger="Manual", request=None): if not frappe.db.get_value(reference_doctype, reference_name): # reference document is either deleted or renamed return elif not trigger and not request and not frappe.db.get_value("Feedback Trigger", { "document_type": reference_doctype }): return elif not trigger and request: trigger = frappe.db.get_value("Feedback Request", request, "feedback_trigger") else: trigger = frappe.db.get_value("Feedback Trigger", { "document_type": reference_doctype }) if not trigger: return feedback_trigger = frappe.get_doc("Feedback Trigger", trigger) doc = frappe.get_doc(reference_doctype, reference_name) context = get_context(doc) recipients = doc.get(feedback_trigger.email_fieldname, None) if feedback_trigger.check_communication: communications = frappe.get_all("Communication", filters={ "reference_doctype": reference_doctype, "reference_name": reference_name, "communication_type": "Communication", "sent_or_received": "Sent" }, fields=["name"]) if len(communications) < 1: frappe.msgprint(_("At least one reply is mandatory before requesting feedback")) return None if recipients and (not feedback_trigger.condition or \ frappe.safe_eval(feedback_trigger.condition, None, context)): subject = feedback_trigger.subject context.update({ "feedback_trigger": feedback_trigger }) if "{" in subject: subject = frappe.render_template(feedback_trigger.subject, context) feedback_request_message = frappe.render_template(feedback_trigger.message, context) return { "subject": subject, "recipients": recipients, "reference_name":doc.name, "reference_doctype":doc.doctype, "message": feedback_request_message, } else: frappe.msgprint(_("Feedback conditions do not match")) return None
def eval_condition_and_formula(self, d, data): try: condition = d.condition.strip() if d.condition else None if condition: if not frappe.safe_eval(condition, self.whitelisted_globals, data): return None amount = d.amount if d.amount_based_on_formula: formula = d.formula.strip() if d.formula else None if formula: amount = frappe.safe_eval(formula, self.whitelisted_globals, data) if amount: data[d.abbr] = amount return amount except NameError as err: frappe.throw(_("Name error: {0}".format(err))) except SyntaxError as err: frappe.throw(_("Syntax error in formula or condition: {0}".format(err))) except Exception as e: frappe.throw(_("Error in formula or condition: {0}".format(e))) raise
def test_fifo(self): frappe.db.set_value("Stock Settings", None, "allow_negative_stock", 1) item_code = "_Test Item 2" warehouse = "_Test Warehouse - _TC" create_stock_reconciliation(item_code="_Test Item 2", warehouse="_Test Warehouse - _TC", qty=0, rate=100) make_stock_entry(item_code=item_code, target=warehouse, qty=1, basic_rate=10) sle = get_sle(item_code = item_code, warehouse = warehouse)[0] self.assertEqual([[1, 10]], frappe.safe_eval(sle.stock_queue)) # negative qty make_stock_entry(item_code=item_code, source=warehouse, qty=2, basic_rate=10) sle = get_sle(item_code = item_code, warehouse = warehouse)[0] self.assertEqual([[-1, 10]], frappe.safe_eval(sle.stock_queue)) # further negative make_stock_entry(item_code=item_code, source=warehouse, qty=1) sle = get_sle(item_code = item_code, warehouse = warehouse)[0] self.assertEqual([[-2, 10]], frappe.safe_eval(sle.stock_queue)) # move stock to positive make_stock_entry(item_code=item_code, target=warehouse, qty=3, basic_rate=20) sle = get_sle(item_code = item_code, warehouse = warehouse)[0] self.assertEqual([[1, 20]], frappe.safe_eval(sle.stock_queue)) # incoming entry with diff rate make_stock_entry(item_code=item_code, target=warehouse, qty=1, basic_rate=30) sle = get_sle(item_code = item_code, warehouse = warehouse)[0] self.assertEqual([[1, 20],[1, 30]], frappe.safe_eval(sle.stock_queue)) frappe.db.set_default("allow_negative_stock", 0)
def evaluate_alert(doc, alert, event): from jinja2 import TemplateError try: if isinstance(alert, string_types): alert = frappe.get_doc("Notification", alert) context = get_context(doc) if alert.condition: if not frappe.safe_eval(alert.condition, None, context): return if event == "Value Change" and not doc.is_new(): if not frappe.db.has_column(doc.doctype, alert.value_changed): alert.db_set('enabled', 0) frappe.log_error( 'Notification {0} has been disabled due to missing field'. format(alert.name)) return doc_before_save = doc.get_doc_before_save() field_value_before_save = doc_before_save.get( alert.value_changed) if doc_before_save else None field_value_before_save = parse_val(field_value_before_save) if (doc.get(alert.value_changed) == field_value_before_save): # value not changed return if event != "Value Change" and not doc.is_new(): # reload the doc for the latest values & comments, # except for validate type event. doc.reload() alert.send(doc) except TemplateError: frappe.throw( _("Error while evaluating Notification {0}. Please fix your template." ).format(alert)) except Exception as e: error_log = frappe.log_error(message=frappe.get_traceback(), title=str(e)) frappe.throw( _("Error in Notification: {}").format( frappe.utils.get_link_to_form('Error Log', error_log.name)))
def calculate_weighted_score(self, weighing_function): my_eval_statement = weighing_function.replace("\r", "").replace("\n", "") for var in self.variables: if var.value: if var.param_name in my_eval_statement: my_eval_statement = my_eval_statement.replace('{' + var.param_name + '}', "{:.2f}".format(var.value)) else: if var.param_name in my_eval_statement: my_eval_statement = my_eval_statement.replace('{' + var.param_name + '}', '0.0') my_eval_statement = my_eval_statement.replace('<','<').replace('>','>') try: weighed_score = frappe.safe_eval(my_eval_statement, None, {'max':max, 'min': min}) except Exception: frappe.throw(_("Could not solve weighted score function. Make sure the formula is valid."),frappe.ValidationError) weighed_score = 0 return weighed_score
def validate_loyalty(doc): def get_dict(obj): if isinstance(obj, frappe.model.document.Document): return obj.as_dict() if isinstance(obj, string_types): return json.loads(obj) if isinstance(obj, dict): return obj return {} code = frappe.db.get_single_value("Optical Store Settings", "loyalty_validation") locals = frappe._dict(pick(["loyalty_points"], get_dict(doc))) if code and not frappe.safe_eval(code, eval_locals=locals): frappe.throw( _( "Loyalty validation failed." "Please correct loyalty fields or contact System Manager." ) )
def eval_tax_slab_condition(self, condition, data): whitelisted_globals = { "int": int, "float": float, "long": int, "round": round, "date": datetime.date } try: condition = condition.strip() if condition: return frappe.safe_eval(condition, whitelisted_globals, data) except NameError as err: frappe.throw(_("Name error: {0}".format(err))) except SyntaxError as err: frappe.throw(_("Syntax error in condition: {0}".format(err))) except Exception as e: frappe.throw(_("Error in formula or condition: {0}".format(e))) raise
def evaluate_alert(doc, alert, event): from jinja2 import TemplateError try: if isinstance(alert, string_types): alert = frappe.get_doc("Notification", alert) context = get_context(doc) if alert.condition: if not frappe.safe_eval(alert.condition, None, context): return if event == "Value Change" and not doc.is_new(): try: db_value = frappe.db.get_value(doc.doctype, doc.name, alert.value_changed) except Exception as e: if frappe.db.is_missing_column(e): alert.db_set('enabled', 0) frappe.log_error( 'Notification {0} has been disabled due to missing field' .format(alert.name)) return else: raise db_value = parse_val(db_value) if (doc.get(alert.value_changed) == db_value) or \ (not db_value and not doc.get(alert.value_changed)): return # value not changed if event != "Value Change" and not doc.is_new(): # reload the doc for the latest values & comments, # except for validate type event. doc = frappe.get_doc(doc.doctype, doc.name) alert.send(doc) except TemplateError: frappe.throw( _("Error while evaluating Notification {0}. Please fix your template." ).format(alert)) except Exception as e: frappe.log_error(message=frappe.get_traceback(), title=str(e)) frappe.throw(_("Error in Notification"))
def set_status_based_on_acceptance_formula(self, reading): if not reading.acceptance_formula: frappe.throw(_("Row #{0}: Acceptance Criteria Formula is required.").format(reading.idx), title=_("Missing Formula")) condition = reading.acceptance_formula data = self.get_formula_evaluation_data(reading) try: result = frappe.safe_eval(condition, None, data) reading.status = "Accepted" if result else "Rejected" except NameError as e: field = frappe.bold(e.args[0].split()[1]) frappe.throw(_("Row #{0}: {1} is not a valid reading field. Please refer to the field description.") .format(reading.idx, field), title=_("Invalid Formula")) except Exception: frappe.throw(_("Row #{0}: Acceptance Criteria Formula is incorrect.").format(reading.idx), title=_("Invalid Formula"))
def evaluate_alert(doc, alert, event): from jinja2 import TemplateError try: if isinstance(alert, basestring): alert = frappe.get_doc("Email Alert", alert) context = get_context(doc) if alert.condition: if not frappe.safe_eval(alert.condition, None, context): return if event == "Value Change" and not doc.is_new(): try: db_value = frappe.db.get_value(doc.doctype, doc.name, alert.value_changed) except frappe.DatabaseOperationalError as e: if e.args[0] == 1054: alert.db_set('enabled', 0) frappe.log_error( 'Email Alert {0} has been disabled due to missing field' .format(alert.name)) return db_value = parse_val(db_value) if (doc.get(alert.value_changed) == db_value) or \ (not db_value and not doc.get(alert.value_changed)): return # value not changed if event != "Value Change" and not doc.is_new(): # reload the doc for the latest values & comments, # except for validate type event. doc = frappe.get_doc(doc.doctype, doc.name) alert.send(doc) except TemplateError: frappe.throw( _("Error while evaluating Email Alert {0}. Please fix your template." ).format(alert)) except Exception, e: frappe.log_error(message=frappe.get_traceback(), title=e) frappe.throw("Error in Email Alert")
def get_mapped_dependency(self, mapping, producer_site, doc): inner_mapping = frappe.get_doc('Document Type Mapping', mapping.mapping) filters = json.loads(mapping.remote_value_filters) for key, value in iteritems(filters): if value.startswith('eval:'): val = frappe.safe_eval(value[5:], dict(frappe=frappe)) filters[key] = val if doc.get(value): filters[key] = doc.get(value) matching_docs = producer_site.get_doc(inner_mapping.remote_doctype, filters=filters) if len(matching_docs): remote_docname = matching_docs[0].get('name') remote_doc = producer_site.get_doc(inner_mapping.remote_doctype, remote_docname) doc = inner_mapping.get_mapping(remote_doc, producer_site, 'Insert').get('doc') return doc return
def get_receiver_list(self, doc, context): ''' return receiver list based on the doc field and role specified ''' receiver_list = [] for recipient in self.recipients: if recipient.condition: if not frappe.safe_eval(recipient.condition, None, context): continue # For sending messages to the owner's mobile phone number if recipient.receiver_by_document_field == 'owner': receiver_list += get_user_info([dict(user_name=doc.get('owner'))], 'mobile_no') # For sending messages to the number specified in the receiver field elif recipient.receiver_by_document_field: receiver_list.append(doc.get(recipient.receiver_by_document_field)) #For sending messages to specified role if recipient.receiver_by_role: receiver_list += get_info_based_on_role(recipient.receiver_by_role, 'mobile_no') return receiver_list
def get_documents_for_today(self): '''get list of documents that will be triggered today''' docs = [] diff_days = self.days_in_advance if self.event=="Days After": diff_days = -diff_days for name in frappe.db.sql_list("""select name from `tab{0}` where DATE(`{1}`) = ADDDATE(DATE(%s), INTERVAL %s DAY)""".format(self.document_type, self.date_changed), (nowdate(), diff_days or 0)): doc = frappe.get_doc(self.document_type, name) if self.condition and not frappe.safe_eval(self.condition, None, get_context(doc)): continue docs.append(doc) return docs
def has_consumer_access(consumer, update_log): """Checks if consumer has completely satisfied all the conditions on the doc""" if isinstance(consumer, str): consumer = frappe.get_doc('Event Consumer', consumer) if not frappe.db.exists(update_log.ref_doctype, update_log.docname): # Delete Log # Check if the last Update Log of this document was read by this consumer last_update_log = frappe.get_all( 'Event Update Log', filters={ 'ref_doctype': update_log.ref_doctype, 'docname': update_log.docname, 'creation': ['<', update_log.creation] }, order_by="creation desc", limit_page_length=1 ) if not len(last_update_log): return False last_update_log = frappe.get_doc( "Event Update Log", last_update_log[0].name) return len([x for x in last_update_log.consumers if x.consumer == consumer.name]) doc = frappe.get_doc(update_log.ref_doctype, update_log.docname) for dt_entry in consumer.consumer_doctypes: if dt_entry.ref_doctype != update_log.ref_doctype: continue if not dt_entry.condition: return True condition: str = dt_entry.condition if condition.startswith("cmd:"): return frappe.call(frappe.get_attr(condition.split("cmd:")[1].strip()), consumer=consumer, update_log=update_log) else: return frappe.safe_eval(condition.eval, frappe._dict(doc=doc)) return False
def calculate_criteria(self): #Get the criteria for crit in self.criteria: #me = "" my_eval_statement = crit.formula.replace("\r", "").replace("\n", "") #for let in my_eval_statement: # me += let.encode('hex') + " " #frappe.msgprint(me) for var in self.variables: if var.value: if var.param_name in my_eval_statement: my_eval_statement = my_eval_statement.replace( '{' + var.param_name + '}', "{:.2f}".format(var.value)) else: if var.param_name in my_eval_statement: my_eval_statement = my_eval_statement.replace( '{' + var.param_name + '}', '0.0') #frappe.msgprint(my_eval_statement ) my_eval_statement = my_eval_statement.replace('<', '<').replace( '>', '>') try: crit.score = min( crit.max_score, max( 0, frappe.safe_eval(my_eval_statement, None, { 'max': max, 'min': min }))) except Exception: frappe.throw( _("Could not solve criteria score function for {0}. Make sure the formula is valid." .format(crit.criteria_name)), frappe.ValidationError) crit.score = 0
def set_status(self, update=False, status=None, update_modified=True): if self.is_new(): if self.get('amended_from'): self.status = 'Draft' return if self.doctype in status_map: _status = self.status if status and update: self.db_set("status", status) sl = status_map[self.doctype][:] sl.reverse() for s in sl: if not s[1]: self.status = s[0] break elif s[1].startswith("eval:"): if frappe.safe_eval( s[1][5:], None, { "self": self.as_dict(), "getdate": getdate, "nowdate": nowdate, "get_value": frappe.db.get_value }): self.status = s[0] break elif getattr(self, s[1])(): self.status = s[0] break if self.status != _status and self.status not in ( "Cancelled", "Partially Ordered", "Ordered", "Issued", "Transferred"): self.add_comment("Label", _(self.status)) if update: self.db_set('status', self.status, update_modified=update_modified)
def set_status_based_on_acceptance_formula(self): for reading in self.readings: if not reading.acceptance_formula: continue condition = reading.acceptance_formula data = {} for i in range(1, 11): field = "reading_" + str(i) data[field] = flt(reading.get(field)) or 0 try: result = frappe.safe_eval(condition, None, data) reading.status = "Accepted" if result else "Rejected" except SyntaxError: frappe.throw(_("Row #{0}: Acceptance Criteria Formula is incorrect.").format(reading.idx), title=_("Invalid Formula")) except NameError as e: field = frappe.bold(e.args[0].split()[1]) frappe.throw(_("Row #{0}: {1} is not a valid reading field. Please refer to the field description.") .format(reading.idx, field), title=_("Invalid Formula"))
def get_list_of_recipients(self, doc, context): recipients = [] cc = [] bcc = [] for recipient in self.recipients: if recipient.condition: if not frappe.safe_eval(recipient.condition, None, context): continue if recipient.email_by_document_field: email_ids_value = doc.get(recipient.email_by_document_field) if validate_email_add(email_ids_value): email_ids = email_ids_value.replace(",", "\n") recipients = recipients + email_ids.split("\n") # else: # print "invalid email" if recipient.cc and "{" in recipient.cc: recipient.cc = frappe.render_template(recipient.cc, context) if recipient.cc: recipient.cc = recipient.cc.replace(",", "\n") cc = cc + recipient.cc.split("\n") if recipient.bcc and "{" in recipient.bcc: recipient.bcc = frappe.render_template(recipient.bcc, context) if recipient.bcc: recipient.bcc = recipient.bcc.replace(",", "\n") bcc = bcc + recipient.bcc.split("\n") #For sending emails to specified role if recipient.email_by_role: emails = get_emails_from_role(recipient.email_by_role) for email in emails: recipients = recipients + email.split("\n") if not recipients and not cc and not bcc: return None, None, None return list(set(recipients)), list(set(cc)), list(set(bcc))
def is_downgrade(sql_file_path, verbose=False): """checks if input db backup will get downgraded on current bench""" from semantic_version import Version head = "INSERT INTO `tabInstalled Application` VALUES" with open(sql_file_path) as f: for line in f: if head in line: # 'line' (str) format: ('2056588823','2020-05-11 18:21:31.488367','2020-06-12 11:49:31.079506','Administrator','Administrator',0,'Installed Applications','installed_applications','Installed Applications',1,'frappe','v10.1.71-74 (3c50d5e) (v10.x.x)','v10.x.x'),('855c640b8e','2020-05-11 18:21:31.488367','2020-06-12 11:49:31.079506','Administrator','Administrator',0,'Installed Applications','installed_applications','Installed Applications',2,'your_custom_app','0.0.1','master') line = line.strip().lstrip(head).rstrip(";").strip() app_rows = frappe.safe_eval(line) # check if iterable consists of tuples before trying to transform apps_list = app_rows if all( isinstance(app_row, (tuple, list, set)) for app_row in app_rows) else (app_rows, ) # 'all_apps' (list) format: [('frappe', '12.x.x-develop ()', 'develop'), ('your_custom_app', '0.0.1', 'master')] all_apps = [x[-3:] for x in apps_list] for app in all_apps: app_name = app[0] app_version = app[1].split(" ")[0] if app_name == "frappe": try: current_version = Version(frappe.__version__) backup_version = Version( app_version[1:] if app_version[0] == "v" else app_version) except ValueError: return False downgrade = backup_version > current_version if verbose and downgrade: print( "Your site will be downgraded from Frappe {0} to {1}" .format(current_version, backup_version)) return downgrade
def get_transitions(doc, workflow=None): '''Return list of possible transitions for the given doc''' if doc.is_new(): return [] frappe.has_permission(doc=doc, ptype='read', throw=True) roles = frappe.get_roles() if not workflow: workflow = get_workflow(doc.doctype) current_state = doc.get(workflow.workflow_state_field) if not current_state: frappe.throw(_('Workflow State not set'), WorkflowStateError) transitions = [] for transition in workflow.transitions: if transition.state == current_state and transition.allowed in roles: if transition.get('condition'): # if condition, evaluate # access to frappe.db.get_value and frappe.db.get_list success = frappe.safe_eval( transition.condition, dict(frappe=frappe._dict( db=frappe._dict( get_value=frappe.db.get_value, get_list=frappe.db.get_list, ), session=frappe.session, )), dict(doc=doc), ) if not success: continue transitions.append(transition.as_dict()) return transitions
def get_users_next_action_data(transitions, doc): user_data_map = {} for transition in transitions: # if self_approval is checked it shouldn't make workflow action and email! if transition.get('allow_self_approval'): continue else: satisfies_condition = True if transition.condition: satisfies_condition = frappe.safe_eval( transition.condition, dict(frappe=frappe._dict(db=frappe._dict( get_value=frappe.db.get_value, get_list=frappe.db.get_list), session=frappe.session)), dict(doc=doc)) # allowed users should also satisfy the transition condition if satisfies_condition: users = get_users_with_role(transition.allowed) filtered_users = filter_allowed_users(users, doc, transition) for user in filtered_users: if not user_data_map.get(user): user_data_map[user] = { 'possible_actions': [], 'email': frappe.db.get_value('User', user, 'email'), } user_data_map[user].get('possible_actions').append({ 'action_name': transition.get('action'), 'action_link': get_workflow_action_url(transition.get('action'), doc, user) }) print(user_data_map) return user_data_map
def evaluate_alert(doc, alert, event): from jinja2 import TemplateError try: if isinstance(alert, string_types): alert = frappe.get_doc("Email Alert", alert) context = get_context(doc) if alert.condition: if not frappe.safe_eval(alert.condition, None, context): return if event=="Value Change" and not doc.is_new(): try: db_value = frappe.db.get_value(doc.doctype, doc.name, alert.value_changed) except pymysql.InternalError as e: if e.args[0]== ER.BAD_FIELD_ERROR: alert.db_set('enabled', 0) frappe.log_error('Email Alert {0} has been disabled due to missing field'.format(alert.name)) return db_value = parse_val(db_value) if (doc.get(alert.value_changed) == db_value) or \ (not db_value and not doc.get(alert.value_changed)): return # value not changed if event != "Value Change" and not doc.is_new(): # reload the doc for the latest values & comments, # except for validate type event. doc = frappe.get_doc(doc.doctype, doc.name) alert.send(doc) except TemplateError: frappe.throw(_("Error while evaluating Email Alert {0}. Please fix your template.").format(alert)) except Exception as e: frappe.log_error(message=frappe.get_traceback(), title=str(e)) frappe.throw(_("Error in Email Alert"))
def get_next_possible_transitions(workflow_name, state, doc=None): transitions = frappe.get_all('Workflow Transition', fields=[ 'allowed', 'action', 'state', 'allow_self_approval', 'next_state', '`condition`' ], filters=[['parent', '=', workflow_name], ['state', '=', state]]) transitions_to_return = [] for transition in transitions: is_next_state_optional = get_state_optional_field_value( workflow_name, transition.next_state) # skip transition if next state of the transition is optional if transition.condition and not frappe.safe_eval( transition.condition, None, {'doc': doc.as_dict()}): continue if is_next_state_optional: continue transitions_to_return.append(transition) return transitions_to_return
def send(self, doc): '''Build recipients and send email alert''' def get_attachment(doc): """ check print settings are attach the pdf """ if not self.attach_print: return None print_settings = frappe.get_doc("Print Settings", "Print Settings") if (doc.docstatus == 0 and not print_settings.allow_print_for_draft) or \ (doc.docstatus == 2 and not print_settings.allow_print_for_cancelled): # ignoring attachment as draft and cancelled documents are not allowed to print status = "Draft" if doc.docstatus == 0 else "Cancelled" frappe.throw(_("""Not allowed to attach {0} document, please enable Allow Print For {0} in Print Settings""".format(status)), title=_("Error in Email Alert")) else: return [frappe.attach_print(doc.doctype, doc.name)] context = get_context(doc) recipients = [] for recipient in self.recipients: if recipient.condition: if not frappe.safe_eval(recipient.condition, None, context): continue if recipient.email_by_document_field: if validate_email_add( doc.get(recipient.email_by_document_field)): recipient.email_by_document_field = doc.get( recipient.email_by_document_field).replace(",", "\n") recipients = recipients + recipient.email_by_document_field.split( "\n") # else: # print "invalid email" if recipient.cc: recipient.cc = recipient.cc.replace(",", "\n") recipients = recipients + recipient.cc.split("\n") #For sending emails to specified role if recipient.email_by_role: emails = get_emails_from_role(recipient.email_by_role) for email in emails: recipients = recipients + email.split("\n") if not recipients: return recipients = list(set(recipients)) subject = self.subject context = {"doc": doc, "alert": self, "comments": None} if self.is_standard: self.load_standard_properties(context) if doc.get("_comments"): context["comments"] = json.loads(doc.get("_comments")) if "{" in subject: subject = frappe.render_template(self.subject, context) attachments = get_attachment(doc) frappe.sendmail(recipients=recipients, subject=subject, message=frappe.render_template(self.message, context), reference_doctype=doc.doctype, reference_name=doc.name, attachments=attachments)
def set_accounting_cards(self, context): """Create accounting cards if checked""" cache = frappe.cache() context.cards = [] for key in ( "income", "expenses_booked", "income_year_to_date", "expense_year_to_date", "bank_balance", "credit_balance", "invoiced_amount", "payables", "sales_orders_to_bill", "purchase_orders_to_bill", "sales_order", "purchase_order", "sales_orders_to_deliver", "purchase_orders_to_receive", "sales_invoice", "purchase_invoice", "new_quotations", "pending_quotations", ): if self.get(key): cache_key = "email_digest:card:{0}:{1}:{2}:{3}".format( self.company, self.frequency, key, self.from_date ) card = cache.get(cache_key) if card: card = frappe.safe_eval(card) else: card = frappe._dict(getattr(self, "get_" + key)()) # format values if card.last_value: card.diff = int(flt(card.value - card.last_value) / card.last_value * 100) if card.diff < 0: card.diff = str(card.diff) card.gain = False else: card.diff = "+" + str(card.diff) card.gain = True if key == "credit_balance": card.last_value = card.last_value * -1 card.last_value = self.fmt_money( card.last_value, False if key in ("bank_balance", "credit_balance") else True ) if card.billed_value: card.billed = int(flt(card.billed_value) / card.value * 100) card.billed = "% Billed " + str(card.billed) if card.delivered_value: card.delivered = int(flt(card.delivered_value) / card.value * 100) if key == "pending_sales_orders": card.delivered = "% Delivered " + str(card.delivered) else: card.delivered = "% Received " + str(card.delivered) if key == "credit_balance": card.value = card.value * -1 card.value = self.fmt_money( card.value, False if key in ("bank_balance", "credit_balance") else True ) cache.set_value(cache_key, card, expires_in_sec=24 * 60 * 60) context.cards.append(card)
def get_filters(self): if self.condition: return frappe.safe_eval(self.condition, dict(frappe=frappe))
def valida_sub_ferias(doc, dias_pagamento, total_dias_trabalho): emp = frappe.get_doc("Employee", doc.employee) for d in doc.earnings: #print d.salary_component print frappe.db.get_value("Salary Component", d.salary_component, "salary_component_abbr") print 'Formula ', d.formula qry_cmpnt = frappe.db.sql( """ select sd.formula from `tabSalary Structure Employee` as se join `tabSalary Detail` as sd on sd.parent = se.parent where se.employee = %s and sd.abbr = %s """, (emp.name, d.abbr), as_dict=True) qry_result = '' if (qry_cmpnt): if qry_cmpnt[0].formula != '': print '1 ', qry_cmpnt[0].formula qry_result = qry_cmpnt[0].formula if frappe.db.get_value("Salary Component", d.salary_component, "salary_component_abbr") == "SB": #Salary Base salariobase = d.amount if (d.salary_component == "Subsidio de Ferias") or (d.abbr == "SF"): print emp.date_of_joining print datetime.date(datetime.datetime.today().year, 12, 31) - emp.date_of_joining print( datetime.date(datetime.datetime.today().year, 12, 31) - emp.date_of_joining).days print "anos ", divmod( (datetime.date(datetime.datetime.today().year, 12, 31) - emp.date_of_joining).days, 365) anos, meses = divmod( (datetime.date(datetime.datetime.today().year, 12, 31) - emp.date_of_joining).days, 365) print anos print meses if anos > 0: print "Tem mais que 1 ano" pass elif meses / 30 < 12: print "Menos que 12 meses!!!!" print "rever a formula !!!", d.amount print date_diff(frappe.utils.nowdate(), emp.date_of_joining) salariohora = ((salariobase * 12) / (52 * 40) ) # em vez de 40horas devem ser 44horas print "Salario Hora ", salariohora meses1 = date_diff(frappe.utils.nowdate(), emp.date_of_joining) / 30 print "Meses ", meses1 diasTrab = meses1 * 2 print "dias Trab ", diasTrab salariodia = salariohora * 8 print "salario Dia ", salariodia subferias = (salariodia * diasTrab) * 0.50 print "salario Ferias ", subferias d.amount = subferias print 'SALARY SLIpppppppppppppppppppp' print qry_result if qry_result != None: print 'payment_days' in qry_result if (qry_result.find('payment_days') != -1 and dias_pagamento != total_dias_trabalho): #found print total_dias_trabalho print dias_pagamento print 'strip ', qry_result.strip() ff = qry_result.replace('payment_days', str(dias_pagamento)) print qry_result.replace('payment_days', str(dias_pagamento)) qry_result = ff if (qry_result.find('total_working_days') != -1): ff = qry_result.replace('total_working_days', str(total_dias_trabalho)) qry_result = ff print frappe.safe_eval(qry_result, None, None) d.amount = frappe.safe_eval(qry_result, None, None) #eval(qry_result) if (qry_result.find('total_working_days') != -1 and dias_pagamento != total_dias_trabalho): ff = qry_result.replace('total_working_days', str(total_dias_trabalho)) qry_result = ff d.amount = frappe.safe_eval(qry_result, None, None) #print frappe.safe_eval(ff,None,None) qry_result = ''
def get_active_service_level_agreement_for(doc): if not frappe.db.get_single_value("Support Settings", "track_service_level_agreement"): return filters = [ ["Service Level Agreement", "active", "=", 1], ["Service Level Agreement", "enable", "=", 1], ] if doc.get("priority"): filters.append( ["Service Level Priority", "priority", "=", doc.get("priority")]) customer = doc.get("customer") or_filters = [[ "Service Level Agreement", "entity", "in", [ customer, get_customer_group(customer), get_customer_territory(customer) ], ]] service_level_agreement = doc.get("service_level_agreement") if service_level_agreement: or_filters = [ [ "Service Level Agreement", "name", "=", doc.get("service_level_agreement") ], ] default_sla_filter = filters + [[ "Service Level Agreement", "default_service_level_agreement", "=", 1 ]] default_sla = frappe.get_all( "Service Level Agreement", filters=default_sla_filter, fields=["name", "default_priority", "condition"], ) filters += [[ "Service Level Agreement", "default_service_level_agreement", "=", 0 ]] agreements = frappe.get_all( "Service Level Agreement", filters=filters, or_filters=or_filters, fields=["name", "default_priority", "condition"], ) # check if the current document on which SLA is to be applied fulfills all the conditions filtered_agreements = [] for agreement in agreements: condition = agreement.get("condition") if not condition or (condition and frappe.safe_eval( condition, None, get_context(doc))): filtered_agreements.append(agreement) # if any default sla filtered_agreements += default_sla return filtered_agreements[0] if filtered_agreements else None
def eval_condition(self, doc): return self.condition and frappe.safe_eval(self.condition, None, {"doc": doc.as_dict()})
def get_filters(self): if self.condition: return frappe.safe_eval(self.condition, get_safe_globals())
def run_webhooks(doc, method): """Run webhooks for this method""" if (frappe.flags.in_import or frappe.flags.in_patch or frappe.flags.in_install or frappe.flags.in_migrate): return if frappe.flags.webhooks_executed is None: frappe.flags.webhooks_executed = {} if frappe.flags.webhooks is None: # load webhooks from cache webhooks = frappe.cache().get_value("webhooks") if webhooks is None: # query webhooks webhooks_list = frappe.get_all( "Webhook", fields=[ "name", "`condition`", "webhook_docevent", "webhook_doctype" ], filters={"enabled": True}, ) # make webhooks map for cache webhooks = {} for w in webhooks_list: webhooks.setdefault(w.webhook_doctype, []).append(w) frappe.cache().set_value("webhooks", webhooks) frappe.flags.webhooks = webhooks # get webhooks for this doctype webhooks_for_doc = frappe.flags.webhooks.get(doc.doctype, None) if not webhooks_for_doc: # no webhooks, quit return def _webhook_request(webhook): if webhook.name not in frappe.flags.webhooks_executed.get( doc.name, []): frappe.enqueue( "frappe.integrations.doctype.webhook.webhook.enqueue_webhook", enqueue_after_commit=True, doc=doc, webhook=webhook, ) # keep list of webhooks executed for this doc in this request # so that we don't run the same webhook for the same document multiple times # in one request frappe.flags.webhooks_executed.setdefault(doc.name, []).append(webhook.name) event_list = [ "on_update", "after_insert", "on_submit", "on_cancel", "on_trash" ] if not doc.flags.in_insert: # value change is not applicable in insert event_list.append("on_change") event_list.append("before_update_after_submit") from frappe.integrations.doctype.webhook.webhook import get_context for webhook in webhooks_for_doc: trigger_webhook = False event = method if method in event_list else None if not webhook.condition: trigger_webhook = True elif frappe.safe_eval(webhook.condition, eval_locals=get_context(doc)): trigger_webhook = True if trigger_webhook and event and webhook.webhook_docevent == event: _webhook_request(webhook)
def get_employee_financial_data(self): self.base = 0.0 self.maximum_loan_amount_cut = 0.0 self.total_deserved_amount = 0.0 self.salary_component_dict = {} self.employee = self.applicant if self.employee: employee_Dict = frappe.db.get_value( "Employee", self.employee, [ "name", "resignation_letter_date", "designation", "status", "department", "relieving_date" ], as_dict=1) if employee_Dict: employeename = employee_Dict.name resignation_letter_date = employee_Dict.resignation_letter_date designation = employee_Dict.designation status = employee_Dict.status department = employee_Dict.department relieving_date = employee_Dict.relieving_date if resignation_letter_date or relieving_date or status == "Left": frappe.throw( _("Sorry....this is employee is going to leave or already left" ), "Employee Status") Salary_Structure_Dict = frappe.db.sql(""" SELECT SSE.base,SD.amount_based_on_formula, SD.formula,SD.amount, SD.`condition`,SD.abbr,SD.salary_component FROM `tabSalary Structure Assignment` as SSE INNER join `tabSalary Structure` as SS on SS.`name` = SSE.salary_structure INNER JOIN `tabSalary Detail` as SD on SD.parent = SS.`name` and SD.parentfield='earnings' and SD.docstatus= '1' and SS.is_active='Yes' and %s >= SSE.from_date and SSE.employee=%s and SS.docstatus='1' ; """, (self.posting_date, self.employee), as_dict=1, debug=False) if Salary_Structure_Dict: for item in Salary_Structure_Dict: self.base = item["base"] self.salary_component_dict["base"] = item["base"] if item["amount_based_on_formula"] == 1: try: condition = item["condition"].strip( ) if item["condition"] else None if condition: if not frappe.safe_eval( condition, None, self.salary_component_dict): return None formula = item["formula"].strip( ) if item["formula"] else None if formula: amount = frappe.safe_eval( formula, None, self.salary_component_dict) self.salary_component_dict[item["abbr"]] = amount self.total_deserved_amount += amount except NameError as err: frappe.throw(_("Name error: {0}".format(err))) except SyntaxError as err: frappe.throw( _("Syntax error in formula or condition: {0}". format(err))) except Exception as e: frappe.throw( _("Error in formula or condition: {0}".format(e))) raise else: self.total_deserved_amount += float(item["amount"]) if self.total_deserved_amount > 0: if int( frappe.db.get_single_value( "HR Settings", "maximum_loan_amount_cut") or 0): self.maximum_loan_amount_cut = float( float( frappe.db.get_single_value( "HR Settings", "maximum_loan_amount_cut")) / 100) * self.total_deserved_amount else: self.maximum_loan_amount_cut = 0.1 * self.total_deserved_amount # msgprint(str(self.maximum_loan_amount_cut)) # msgprint(str(self.total_deserved_amount)) # frappe.throw("not saved") else: frappe.throw( _("Sorry....this is employee has no salary structure "), "Employee Salary Structure ") return self.maximum_loan_amount_cut
def test_safe_eval(self): self.assertEqual(frappe.safe_eval('1+1'), 2) self.assertRaises(AttributeError, frappe.safe_eval, 'frappe.utils.os.path', get_safe_globals())
def send(self, doc): '''Build recipients and send email alert''' from email.utils import formataddr def get_attachment(doc): """ check print settings are attach the pdf """ if not self.attach_print: return None print_settings = frappe.get_doc("Print Settings", "Print Settings") if (doc.docstatus == 0 and not print_settings.allow_print_for_draft) or \ (doc.docstatus == 2 and not print_settings.allow_print_for_cancelled): # ignoring attachment as draft and cancelled documents are not allowed to print status = "Draft" if doc.docstatus == 0 else "Cancelled" frappe.throw(_("""Not allowed to attach {0} document, please enable Allow Print For {0} in Print Settings""".format(status)), title=_("Error in Email Alert")) else: return [{"print_format_attachment":1, "doctype":doc.doctype, "name": doc.name, "print_format":self.print_format, "print_letterhead": print_settings.with_letterhead}] context = get_context(doc) recipients = [] sender = "" for recipient in self.recipients: if recipient.condition: if not frappe.safe_eval(recipient.condition, None, context): continue if recipient.email_by_document_field: email_ids_value = doc.get(recipient.email_by_document_field) if validate_email_add(email_ids_value): email_ids = email_ids_value.replace(",", "\n") recipients = recipients + email_ids.split("\n") # else: # print "invalid email" if recipient.cc: recipient.cc = recipient.cc.replace(",", "\n") recipients = recipients + recipient.cc.split("\n") #For sending emails to specified role if recipient.email_by_role: emails = get_emails_from_role(recipient.email_by_role) for email in emails: recipients = recipients + email.split("\n") if not recipients: return recipients = list(set(recipients)) subject = self.subject context = {"doc": doc, "alert": self, "comments": None} if self.sender: sender = formataddr((self.sender, self.sender_email)) if self.is_standard: self.load_standard_properties(context) if doc.get("_comments"): context["comments"] = json.loads(doc.get("_comments")) if "{" in subject: subject = frappe.render_template(self.subject, context) attachments = get_attachment(doc) frappe.sendmail(recipients=recipients, subject=subject, message= frappe.render_template(self.message, context), sender = sender, reference_doctype = doc.doctype, reference_name = doc.name, attachments = attachments, print_letterhead = ((attachments and attachments[0].get('print_letterhead')) or False)) if self.set_property_after_alert: frappe.db.set_value(doc.doctype, doc.name, self.set_property_after_alert, self.property_value, update_modified = False) doc.set(self.set_property_after_alert, self.property_value)
def get_context(self, context): '''Build context to render the `web_form.html` template''' self.set_web_form_module() context._login_required = False if self.login_required and frappe.session.user == "Guest": context._login_required = True doc, delimeter = make_route_string(frappe.form_dict) context.doc = doc context.delimeter = delimeter # check permissions if frappe.session.user == "Guest" and frappe.form_dict.name: frappe.throw( _("You need to be logged in to access this {0}.").format( self.doc_type), frappe.PermissionError) if frappe.form_dict.name and not has_web_form_permission( self.doc_type, frappe.form_dict.name): frappe.throw( _("You don't have the permissions to access this document"), frappe.PermissionError) self.reset_field_parent() if self.is_standard: self.use_meta_fields() if not context._login_required: if self.allow_edit: if self.allow_multiple: if not frappe.form_dict.name and not frappe.form_dict.new: # list data is queried via JS context.is_list = True else: if frappe.session.user != 'Guest' and not frappe.form_dict.name: frappe.form_dict.name = frappe.db.get_value( self.doc_type, {"owner": frappe.session.user}, "name") if not frappe.form_dict.name: # only a single doc allowed and no existing doc, hence new frappe.form_dict.new = 1 # always render new form if login is not required or doesn't allow editing existing ones if not self.login_required or not self.allow_edit: frappe.form_dict.new = 1 self.load_document(context) context.parents = self.get_parents(context) if self.breadcrumbs: context.parents = frappe.safe_eval(self.breadcrumbs, {"_": _}) context.has_header = ((frappe.form_dict.name or frappe.form_dict.new) and (frappe.session.user != "Guest" or not self.login_required)) if context.success_message: context.success_message = frappe.db.escape( context.success_message.replace("\n", "<br>")).strip("'") self.add_custom_context_and_script(context) if not context.max_attachment_size: context.max_attachment_size = get_max_file_size() / 1024 / 1024 context.show_in_grid = self.show_in_grid self.load_translations(context)
return {"sms_sent": query[0][0] or 0, "sms_balance": sms_balance} _get_receiver_list = compose( list, unique, validate_receiver_nos, lambda x: x.replace(",", "\n").split(), frappe.utils.cstr, ) _eval_dynamic_params = partial( valmap, lambda x: frappe.safe_eval( x, eval_globals=frappe._dict(frappe=frappe._dict(utils=frappe.utils)) ), ) def _make_headers(ss, sx): get_dynamic_headers = compose( _eval_dynamic_params, lambda x: dissoc(x, "Accept"), get_headers ) return merge(get_headers(ss), get_dynamic_headers(sx)) def _make_params(ss, sx): get_param_payload = compose( lambda params: reduce( lambda a, x: merge(a, {x.parameter: x.value}), params, {}