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 submit_cancel_or_update_docs(doctype, docnames, action='submit', data=None): docnames = frappe.parse_json(docnames) if data: data = frappe.parse_json(data) failed = [] for i, d in enumerate(docnames, 1): doc = frappe.get_doc(doctype, d) try: message = '' if action == 'submit' and doc.docstatus==0: doc.submit() message = _('Submiting {0}').format(doctype) elif action == 'cancel' and doc.docstatus==1: doc.cancel() message = _('Cancelling {0}').format(doctype) elif action == 'update' and doc.docstatus < 2: doc.update(data) doc.save() message = _('Updating {0}').format(doctype) else: failed.append(d) frappe.db.commit() show_progress(docnames, message, i, d) except Exception: failed.append(d) frappe.db.rollback() return failed
def __init__(self, template, faker_seed=None, faker_lang=None): super(JSONGenerator, self).__init__() if isinstance(template, string_types): template = frappe.parse_json(template) self.template = template self.faker = Faker(faker_lang) self.unique_values = frappe._dict()
def get_all_suppliers(date_range, company, field, limit=None): if field == "outstanding_amount": filters = [['docstatus', '=', '1'], ['company', '=', company]] if date_range: date_range = frappe.parse_json(date_range) filters.append( ['posting_date', 'between', [date_range[0], date_range[1]]]) return frappe.db.get_all( 'Purchase Invoice', fields=['supplier as name', 'sum(outstanding_amount) as value'], filters=filters, group_by='supplier', order_by='value desc', limit=limit) else: if field == "total_purchase_amount": select_field = "sum(purchase_order_item.base_net_amount)" elif field == "total_qty_purchased": select_field = "sum(purchase_order_item.stock_qty)" date_condition = get_date_condition(date_range, 'purchase_order.modified') return frappe.db.sql(""" select purchase_order.supplier as name, {0} as value FROM `tabPurchase Order` as purchase_order LEFT JOIN `tabPurchase Order Item` as purchase_order_item ON purchase_order.name = purchase_order_item.parent where purchase_order.docstatus = 1 {1} and purchase_order.company = %s group by purchase_order.supplier order by value DESC limit %s""".format(select_field, date_condition), (company, cint(limit)), as_dict=1) #nosec
def get_kanban_column_order_and_index(board, colname): for i, col in enumerate(board.columns): if col.column_name == colname: col_order = frappe.parse_json(col.order) col_idx = i return col_order, col_idx
def update_hidden_modules(category_map): category_map = frappe.parse_json(category_map) home_settings = get_home_settings() saved_hidden_modules = home_settings.hidden_modules or [] for category in category_map: config = frappe._dict(category_map[category]) saved_hidden_modules += config.removed or [] saved_hidden_modules = [ d for d in saved_hidden_modules if d not in (config.added or []) ] if home_settings.get('modules_by_category' ) and home_settings.modules_by_category.get( category): module_placement = [ d for d in (config.added or []) if d not in home_settings.modules_by_category[category] ] home_settings.modules_by_category[category] += module_placement home_settings.hidden_modules = saved_hidden_modules set_home_settings(home_settings) return get_desktop_settings()
def create_if_not_exists(doc): '''Create records if they dont exist. Will check for uniqueness by checking if a record exists with these field value pairs :param doc: dict of field value pairs. can be a list of dict for multiple records. ''' if not frappe.local.dev_server: frappe.throw('This method can only be accessed in development', frappe.PermissionError) doc = frappe.parse_json(doc) if not isinstance(doc, list): docs = [doc] else: docs = doc names = [] for doc in docs: doc = frappe._dict(doc) filters = doc.copy() filters.pop('doctype') name = frappe.db.exists(doc.doctype, filters) if not name: d = frappe.get_doc(doc) d.insert(ignore_permissions=True) name = d.name names.append(name) return names
def delete_prepared_reports(reports): reports = frappe.parse_json(reports) for report in reports: frappe.delete_doc('Prepared Report', report['name'], ignore_permissions=True, delete_permanently=True)
def get_additional_conditions(from_date, ignore_closing_entries, filters): additional_conditions = [] accounting_dimensions = get_accounting_dimensions(as_list=False) if filters: if filters.get("project"): if not isinstance(filters.get("project"), list): filters.project = frappe.parse_json(filters.get("project")) additional_conditions.append("b.project in %(project)s") if filters.get("cost_center"): filters.cost_center = get_cost_centers_with_children( filters.cost_center) additional_conditions.append("b.cost_center in %(cost_center)s") if accounting_dimensions: for dimension in accounting_dimensions: if filters.get(dimension.fieldname): if frappe.get_cached_value('DocType', dimension.document_type, 'is_tree'): filters[dimension.fieldname] = get_dimension_with_children( dimension.document_type, filters.get(dimension.fieldname)) additional_conditions.append("{0} in %({0})s".format( dimension.fieldname)) else: additional_conditions.append("{0} in (%({0})s)".format( dimension.fieldname)) return " and {}".format( " and ".join(additional_conditions)) if additional_conditions else ""
def get_additional_conditions(from_date, ignore_closing_entries, filters): additional_conditions = [] accounting_dimensions = get_accounting_dimensions() if ignore_closing_entries: additional_conditions.append("ifnull(voucher_type, '')!='Period Closing Voucher'") if from_date: additional_conditions.append("posting_date >= %(from_date)s") if filters: if filters.get("project"): if not isinstance(filters.get("project"), list): filters.project = frappe.parse_json(filters.get("project")) additional_conditions.append("project in %(project)s") if filters.get("cost_center"): filters.cost_center = get_cost_centers_with_children(filters.cost_center) additional_conditions.append("cost_center in %(cost_center)s") if filters.get("finance_book"): if filters.get("include_default_book_entries"): additional_conditions.append("finance_book in (%(finance_book)s, %(company_fb)s)") else: additional_conditions.append("finance_book in (%(finance_book)s)") if accounting_dimensions: for dimension in accounting_dimensions: if filters.get(dimension): additional_conditions.append("{0} in (%({0})s)".format(dimension)) return " and {}".format(" and ".join(additional_conditions)) if additional_conditions else ""
def execute(): if not frappe.db.table_exists('Dashboard Chart'): return charts_to_modify = frappe.db.get_all('Dashboard Chart', fields = ['name', 'filters_json', 'document_type'], filters = {'chart_type': ['not in', ['Report', 'Custom']]} ) for chart in charts_to_modify: old_filters = frappe.parse_json(chart.filters_json) if chart.filters_json and isinstance(old_filters, dict): new_filters = [] doctype = chart.document_type for key in old_filters.keys(): filter_value = old_filters[key] if isinstance(filter_value, list): new_filters.append([doctype, key, filter_value[0], filter_value[1], 0]) else: new_filters.append([doctype, key, '=', filter_value, 0]) new_filters_json = json.dumps(new_filters) frappe.db.set_value('Dashboard Chart', chart.name, 'filters_json', new_filters_json)
def execute(): if not frappe.db.table_exists("Dashboard Chart"): return charts_to_modify = frappe.db.get_all( "Dashboard Chart", fields=["name", "filters_json", "document_type"], filters={"chart_type": ["not in", ["Report", "Custom"]]}, ) for chart in charts_to_modify: old_filters = frappe.parse_json(chart.filters_json) if chart.filters_json and isinstance(old_filters, dict): new_filters = [] doctype = chart.document_type for key in old_filters.keys(): filter_value = old_filters[key] if isinstance(filter_value, list): new_filters.append( [doctype, key, filter_value[0], filter_value[1], 0]) else: new_filters.append([doctype, key, "=", filter_value, 0]) new_filters_json = json.dumps(new_filters) frappe.db.set_value("Dashboard Chart", chart.name, "filters_json", new_filters_json)
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 execute(filters=None): if not filters: return [], [] account_details = {} if filters and filters.get( "print_in_account_currency") and not filters.get("account"): frappe.throw(_("Select an account to print in account currency")) for acc in frappe.db.sql("""select name, is_group from tabAccount""", as_dict=1): account_details.setdefault(acc.name, acc) if filters.get("party"): filters.party = frappe.parse_json(filters.get("party")) validate_filters(filters, account_details) validate_party(filters) filters = set_account_currency(filters) columns = get_columns(filters) update_translations() res = get_result(filters, account_details) return columns, res
def get_version(doctype, doc_name, frequency, user): timeline = [] filters = get_filters("docname", doc_name, frequency, user) version = frappe.get_all( "Version", filters=filters, fields=["ref_doctype", "data", "modified", "modified", "modified_by"]) if version: for v in version: change = frappe.parse_json(v.data) time = frappe.utils.format_datetime(v.modified, "hh:mm a") timeline_items = [] if change.changed: timeline_items = get_field_changed(change.changed, time, doctype, doc_name, v) if change.row_changed: timeline_items = get_row_changed(change.row_changed, time, doctype, doc_name, v) if change.added: timeline_items = get_added_row(change.added, time, doctype, doc_name, v) timeline = timeline + timeline_items return timeline
def create_lead_for_item_inquiry(lead, subject, message): lead = frappe.parse_json(lead) lead_doc = frappe.new_doc("Lead") for fieldname in ("lead_name", "company_name", "email_id", "phone"): lead_doc.set(fieldname, lead.get(fieldname)) lead_doc.set("lead_owner", "") if not frappe.db.exists("Lead Source", "Product Inquiry"): frappe.get_doc({ "doctype": "Lead Source", "source_name": "Product Inquiry" }).insert(ignore_permissions=True) lead_doc.set("source", "Product Inquiry") try: lead_doc.save(ignore_permissions=True) except frappe.exceptions.DuplicateEntryError: frappe.clear_messages() lead_doc = frappe.get_doc("Lead", {"email_id": lead["email_id"]}) lead_doc.add_comment( "Comment", text=""" <div> <h5>{subject}</h5> <p>{message}</p> </div> """.format(subject=subject, message=message), ) return lead_doc
def make_log(**kwargs): tags = kwargs.get("tags") or [] if isinstance(tags, string_types): if tags.startswith("["): tags = frappe.parse_json(tags) else: tags = [tags] tags.append(frappe.local.site) kwargs["tags"] = frappe.as_json(tags) header = requests.utils.default_headers() header.update({ "Accept": "application/json", 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36' }) r = requests.post( frappe.get_site_config().get("log_url"), json=frappe._dict( cmd="renovation_logging.api.make_log", user=frappe.session.user, **kwargs ), headers=header ) if not r.ok: frappe.throw(r.text) return r.json().get("message")
def __init__(self, doctype, data_import=None, file_path=None, content=None, console=False): self.doctype = doctype self.template_options = frappe._dict({"remap_column": {}}) self.console = console if data_import: self.data_import = data_import if self.data_import.template_options: template_options = frappe.parse_json( self.data_import.template_options) self.template_options.update(template_options) self.import_type = self.data_import.import_type else: self.data_import = None self.import_type = self.import_type or INSERT self.header_row = None self.data = None # used to store date formats guessed from data rows per column self._guessed_date_formats = {} # used to store eta during import self.last_eta = 0 # used to collect warnings during template parsing # and show them to user self.warnings = [] self.meta = frappe.get_meta(doctype) self.prepare_content(file_path, content) self.parse_data_from_template()
def update_itemised_tax_data(doc): if not doc.taxes: return itemised_tax = get_itemised_tax(doc.taxes) for row in doc.items: tax_rate = 0.0 item_tax_rate = 0.0 if row.item_tax_rate: item_tax_rate = frappe.parse_json(row.item_tax_rate) # First check if tax rate is present # If not then look up in item_wise_tax_detail if item_tax_rate: for account, rate in iteritems(item_tax_rate): tax_rate += rate elif row.item_code and itemised_tax.get(row.item_code): tax_rate = sum([ tax.get("tax_rate", 0) for d, tax in itemised_tax.get(row.item_code).items() ]) meta = frappe.get_meta(row.doctype) if meta.has_field("tax_rate"): row.tax_rate = flt(tax_rate, row.precision("tax_rate")) row.tax_amount = flt((row.net_amount * tax_rate) / 100, row.precision("net_amount")) row.total_amount = flt((row.net_amount + row.tax_amount), row.precision("total_amount"))
def make_log(**kwargs): tags = kwargs.get("tags") or [] if isinstance(tags, string_types): if tags.startswith("["): tags = frappe.parse_json(tags) else: tags = [tags] tags.append(frappe.local.site) kwargs["tags"] = frappe.as_json(tags) header = requests.utils.default_headers() header.update({ "Accept": "application/json", 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36' }) if not frappe.get_site_config().get("log_url"): # frappe.local.request will exist when invoked over API # background workers wont have 'request' if hasattr(frappe.local, "request"): frappe.throw("No Log URL is mentioned in the site_config") return "no-log-url" r = requests.post(frappe.get_site_config().get("log_url"), json=frappe._dict(cmd="renovation_logging.api.make_log", user=frappe.session.user, **kwargs), headers=header) if not r.ok: frappe.throw(r.text) return r.json().get("message")
def __init__(self, doctype, data_import=None, file_path=None, import_type=None, console=False): self.doctype = doctype self.console = console self.data_import = data_import if not self.data_import: self.data_import = frappe.get_doc(doctype="Data Import") if import_type: self.data_import.import_type = import_type self.template_options = frappe.parse_json( self.data_import.template_options or "{}") self.import_type = self.data_import.import_type self.import_file = ImportFile( doctype, file_path or data_import.google_sheets_url or data_import.import_file, self.template_options, self.import_type, )
def add_new_address(doc): doc = frappe.parse_json(doc) doc.update({'doctype': 'Address'}) address = frappe.get_doc(doc) address.save(ignore_permissions=True) return address
def create_number_card(args): args = frappe.parse_json(args) doc = frappe.new_doc('Number Card') doc.update(args) doc.insert(ignore_permissions=True) return doc
def validate_link(doctype: str, docname: str, fields=None): if not isinstance(doctype, str): frappe.throw(_("DocType must be a string")) if not isinstance(docname, str): frappe.throw(_("Document Name must be a string")) if doctype != "DocType" and not (frappe.has_permission( doctype, "select") or frappe.has_permission(doctype, "read")): frappe.throw( _("You do not have Read or Select Permissions for {}").format( frappe.bold(doctype)), frappe.PermissionError, ) values = frappe._dict() values.name = frappe.db.get_value(doctype, docname, cache=True) fields = frappe.parse_json(fields) if not values.name or not fields: return values try: values.update(get_value(doctype, fields, docname)) except frappe.PermissionError: frappe.clear_last_message() frappe.msgprint( _("You need {0} permission to fetch values from {1} {2}").format( frappe.bold(_("Read")), frappe.bold(doctype), frappe.bold(docname)), title=_("Cannot Fetch Values"), indicator="orange", ) return values
def submit_payment(self): if frappe.db.exists( "Payment Entry", dict(reference_no=self.integration_request.get("service_id"), docstatus=0)): posting_date = getdate( frappe.parse_json( self.integration_request.data).get("created_at")) self.payment_entry = frappe.get_doc( "Payment Entry", dict(reference_no=self.integration_request.get("service_id"), docstatus=0)) self.payment_entry.posting_date = posting_date self.payment_entry.reference_date = posting_date if hasattr(self, 'add_fees_before_submission'): self.add_fees_before_submission() self.payment_entry.flags.ignore_permissions = True self.payment_entry.submit() self.trigger_subscription_events() self.set_as_completed() self.close_related_payment_request() elif frappe.db.exists( "Payment Entry", dict(reference_no=self.integration_request.get("service_id"), docstatus=1)): self.set_as_completed() self.close_related_payment_request() else: self.set_as_failed( _("Payment entry with reference {0} not found").format( self.integration_request.get("service_id")))
def execute(filters=None): if not filters: return [], [] account_details = {} if filters and filters.get('print_in_account_currency') and \ not filters.get('account'): frappe.throw(_("Select an account to print in account currency")) for acc in frappe.db.sql("""select name, is_group from tabAccount""", as_dict=1): account_details.setdefault(acc.name, acc) if filters.get('party'): filters.party = frappe.parse_json(filters.get("party")) validate_filters(filters, account_details) validate_party(filters) filters = set_account_currency(filters) res, currency_list = get_result(filters, account_details) columns = get_columns(filters,currency_list) #frappe.msgprint("filters=========={0},account_details=========={1},res=========={2}".format(filters,account_details,res)) return columns, res
def get_request_form_data(): if frappe.local.form_dict.data is None: data = frappe.safe_decode(frappe.local.request.get_data()) else: data = frappe.local.form_dict.data return frappe.parse_json(data)
def get_all_customers(date_range, company, field, limit=None): if field == "outstanding_amount": filters = [['docstatus', '=', '1'], ['company', '=', company]] if date_range: date_range = frappe.parse_json(date_range) filters.append([ 'posting_date', '>=', 'between', [date_range[0], date_range[1]] ]) return frappe.db.get_all( 'Sales Invoice', fields=['customer as name', 'sum(outstanding_amount) as value'], filters=filters, group_by='customer', order_by='value desc', limit=limit) else: if field == "total_sales_amount": select_field = "sum(so_item.base_net_amount)" elif field == "total_qty_sold": select_field = "sum(so_item.stock_qty)" date_condition = get_date_condition(date_range, 'so.transaction_date') return frappe.db.sql(""" select so.customer as name, {0} as value FROM `tabSales Order` as so JOIN `tabSales Order Item` as so_item ON so.name = so_item.parent where so.docstatus = 1 {1} and so.company = %s group by so.customer order by value DESC limit %s """.format(select_field, date_condition), (company, cint(limit)), as_dict=1)
def get_transitions(doc, workflow=None, raise_exception=False): '''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: if raise_exception: raise WorkflowStateError else: frappe.throw(_('Workflow State not set'), WorkflowStateError) transitions = [] for transition in workflow.transitions: if transition.state == current_state and transition.allowed in roles: if not is_transition_condition_satisfied(transition, doc): continue transitions.append(transition.as_dict()) return transitions
def redirect_to_gocardless(data): data = frappe.parse_json(data) gateway_controller = get_gateway_controller(data["reference_doctype"], data["reference_docname"]) client = frappe.get_doc("GoCardless Settings", gateway_controller).initialize_client() success_url = data.get("success_url") if not success_url: success_url = get_url("./integrations/gocardless_confirmation?reference_doctype="\ + data["reference_doctype"] + "&reference_docname=" + data["reference_docname"]) try: redirect_flow = client.redirect_flows.create( params={ "description": _("Pay {0}").format( fmt_money(data['amount'], currency=data['currency'])), "session_token": data["reference_docname"], "success_redirect_url": success_url, "prefilled_customer": get_prefilled_customer(data) }) return {"redirect_to": redirect_flow.redirect_url} except Exception as e: frappe.log_error(e, "GoCardless Payment Error") return {"redirect_to": '/integrations/payment-failed'}
def get_events(doctype, start, end, field_map, filters=None, fields=None): field_map = frappe._dict(json.loads(field_map)) fields = frappe.parse_json(fields) doc_meta = frappe.get_meta(doctype) for d in doc_meta.fields: if d.fieldtype == "Color": field_map.update({"color": d.fieldname}) if filters: filters = json.loads(filters or '') if not fields: fields = [field_map.start, field_map.end, field_map.title, 'name'] if field_map.color: fields.append(field_map.color) start_date = "ifnull(%s, '0001-01-01 00:00:00')" % field_map.start end_date = "ifnull(%s, '2199-12-31 00:00:00')" % field_map.end filters += [ [doctype, start_date, '<=', end], [doctype, end_date, '>=', start], ] return frappe.get_list(doctype, fields=fields, filters=filters)
def get_group_by_count(doctype, current_filters, field): current_filters = frappe.parse_json(current_filters) subquery_condition = '' subquery = frappe.get_all(doctype, filters=current_filters, return_query=True) if field == 'assigned_to': subquery_condition = ' and `tabToDo`.reference_name in ({subquery})'.format( subquery=subquery) return frappe.db.sql( """select `tabToDo`.owner as name, count(*) as count from `tabToDo`, `tabUser` where `tabToDo`.status!='Cancelled' and `tabToDo`.owner = `tabUser`.name and `tabUser`.user_type = 'System User' {subquery_condition} group by `tabToDo`.owner order by count desc limit 50""".format(subquery_condition=subquery_condition), as_dict=True) else: return frappe.db.get_list( doctype, filters=current_filters, group_by='`tab{0}`.{1}'.format(doctype, field), fields=['count(*) as count', '`{}` as name'.format(field)], order_by='count desc', limit=50, )
def apply_workflow(doc, action): '''Allow workflow action on the current doc''' doc = frappe.get_doc(frappe.parse_json(doc)) workflow = get_workflow(doc.doctype) transitions = get_transitions(doc, workflow) user = frappe.session.user # find the transition transition = None for t in transitions: if t.action == action: transition = t if not transition: frappe.throw(_("Not a valid Workflow Action"), WorkflowTransitionError) if not has_approval_access(user, doc, transition): frappe.throw(_("Self approval is not allowed")) # update workflow state field doc.set(workflow.workflow_state_field, transition.next_state) # find settings for the next state next_state = [d for d in workflow.states if d.state == transition.next_state][0] # update any additional field if next_state.update_field: doc.set(next_state.update_field, next_state.update_value) new_docstatus = cint(next_state.doc_status) if doc.docstatus == 0 and new_docstatus == 0: doc.save() elif doc.docstatus == 0 and new_docstatus == 1: doc.submit() elif doc.docstatus == 1 and new_docstatus == 1: doc.save() elif doc.docstatus == 1 and new_docstatus == 2: doc.cancel() else: frappe.throw(_('Illegal Document Status for {0}').format(next_state.state)) doc.add_comment('Workflow', _(next_state.state)) return doc