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 get_children(doctype, parent=None, is_root=False, **filters): if not parent or parent=="BOM": frappe.msgprint(_('Please select a BOM')) return if frappe.form_dict.parent: bom_doc = frappe.get_doc("BOM", frappe.form_dict.parent) frappe.has_permission("BOM", doc=bom_doc, throw=True) bom_items = frappe.get_all('BOM Item', fields=['item_code', 'bom_no as value', 'stock_qty'], filters=[['parent', '=', frappe.form_dict.parent]], order_by='idx') item_names = tuple(d.get('item_code') for d in bom_items) items = frappe.get_list('Item', fields=['image', 'description', 'name'], filters=[['name', 'in', item_names]]) # to get only required item dicts for bom_item in bom_items: # extend bom_item dict with respective item dict bom_item.update( # returns an item dict from items list which matches with item_code next(item for item in items if item.get('name') == bom_item.get('item_code')) ) bom_item.expandable = 0 if bom_item.value in ('', None) else 1 return bom_items
def get_batch_qty(batch_no=None, warehouse=None, item_code=None): '''Returns batch actual qty if warehouse is passed, or returns dict of qty by warehouse if warehouse is None The user must pass either batch_no or batch_no + warehouse or item_code + warehouse :param batch_no: Optional - give qty for this batch no :param warehouse: Optional - give qty for this warehouse :param item_code: Optional - give qty for this item''' frappe.has_permission('Batch', throw=True) out = 0 if batch_no and warehouse: out = float(frappe.db.sql("""select sum(actual_qty) from `tabStock Ledger Entry` where warehouse=%s and batch_no=%s""", (warehouse, batch_no))[0][0] or 0) if batch_no and not warehouse: out = frappe.db.sql('''select warehouse, sum(actual_qty) as qty from `tabStock Ledger Entry` where batch_no=%s group by warehouse''', batch_no, as_dict=1) if not batch_no and item_code and warehouse: out = frappe.db.sql('''select batch_no, sum(actual_qty) as qty from `tabStock Ledger Entry` where item_code = %s and warehouse=%s group by batch_no''', (item_code, warehouse), as_dict=1) return out
def get_account_details(account, date): frappe.has_permission('Payment Entry', throw=True) return frappe._dict({ "account_currency": get_account_currency(account), "account_balance": get_balance_on(account, date), "account_type": frappe.db.get_value("Account", account, "account_type") })
def check_file_permission(file_url): for file in frappe.get_all("File", filters={"file_url": file_url, "is_private": 1}, fields=["name", "attached_to_doctype", "attached_to_name"]): if (frappe.has_permission("File", ptype="read", doc=file.name) or frappe.has_permission(file.attached_to_doctype, ptype="read", doc=file.attached_to_name)): return True raise frappe.PermissionError
def has_permission(doc, ptype, user): if ptype=="read": if doc.reference_doctype and doc.reference_name: if frappe.has_permission(doc.reference_doctype, ptype="read", doc=doc.reference_name): return True if doc.timeline_doctype and doc.timeline_name: if frappe.has_permission(doc.timeline_doctype, ptype="read", doc=doc.timeline_name): return True
def get_dashboard_data(name): '''load dashboard related data''' frappe.has_permission(doc=frappe.get_doc('Item', name), throw=True) from frappe.desk.notifications import get_open_count return { 'count': get_open_count('Item', name), 'timeline_data': get_timeline_data(name), }
def get_open_count(doctype, name, items=[]): '''Get open count for given transactions and filters :param doctype: Reference DocType :param name: Reference Name :param transactions: List of transactions (json/dict) :param filters: optional filters (json/list)''' if frappe.flags.in_migrate or frappe.flags.in_install: return { 'count': [] } frappe.has_permission(doc=frappe.get_doc(doctype, name), throw=True) meta = frappe.get_meta(doctype) links = meta.get_dashboard_data() # compile all items in a list if not items: for group in links.transactions: items.extend(group.get('items')) if not isinstance(items, list): items = json.loads(items) out = [] for d in items: if d in links.get('internal_links', {}): # internal link continue filters = get_filters_for(d) fieldname = links.get('non_standard_fieldnames', {}).get(d, links.fieldname) data = {'name': d} if filters: # get the fieldname for the current document # we only need open documents related to the current document filters[fieldname] = name total = len(frappe.get_all(d, fields='name', filters=filters, limit=100, distinct=True, ignore_ifnull=True)) data['open_count'] = total total = len(frappe.get_all(d, fields='name', filters={fieldname: name}, limit=100, distinct=True, ignore_ifnull=True)) data['count'] = total out.append(data) out = { 'count': out, } module = frappe.get_meta_module(doctype) if hasattr(module, 'get_timeline_data'): out['timeline_data'] = module.get_timeline_data(doctype, name) return out
def get_stock_balance_for(item_code, warehouse, posting_date, posting_time): frappe.has_permission("Stock Reconciliation", "write", throw = True) qty, rate = get_stock_balance(item_code, warehouse, posting_date, posting_time, with_valuation_rate=True) return { 'qty': qty, 'rate': rate }
def sync(self): """Create and execute Data Migration Run for Hub Sync plan""" frappe.has_permission('Hub Settings', throw=True) doc = frappe.get_doc({ 'doctype': 'Data Migration Run', 'data_migration_plan': 'Hub Sync', 'data_migration_connector': 'Hub Connector' }).insert() doc.run()
def make_depreciation_entry(asset_name, date=None): frappe.has_permission('Journal Entry', throw=True) if not date: date = today() asset = frappe.get_doc("Asset", asset_name) fixed_asset_account, accumulated_depreciation_account, depreciation_expense_account = \ get_depreciation_accounts(asset) depreciation_cost_center, depreciation_series = frappe.get_cached_value('Company', asset.company, ["depreciation_cost_center", "series_for_depreciation_entry"]) depreciation_cost_center = asset.cost_center or depreciation_cost_center for d in asset.get("schedules"): if not d.journal_entry and getdate(d.schedule_date) <= getdate(date): je = frappe.new_doc("Journal Entry") je.voucher_type = "Depreciation Entry" je.naming_series = depreciation_series je.posting_date = d.schedule_date je.company = asset.company je.finance_book = d.finance_book je.remark = "Depreciation Entry against {0} worth {1}".format(asset_name, d.depreciation_amount) je.append("accounts", { "account": accumulated_depreciation_account, "credit_in_account_currency": d.depreciation_amount, "reference_type": "Asset", "reference_name": asset.name }) je.append("accounts", { "account": depreciation_expense_account, "debit_in_account_currency": d.depreciation_amount, "reference_type": "Asset", "reference_name": asset.name, "cost_center": depreciation_cost_center }) je.flags.ignore_permissions = True je.submit() d.db_set("journal_entry", je.name) idx = cint(d.finance_book_id) finance_books = asset.get('finance_books')[idx - 1] finance_books.value_after_depreciation -= d.depreciation_amount finance_books.db_update() asset.set_status() return asset
def send_reminder(): frappe.has_permission('GST Settings', throw=True) last_sent = frappe.db.get_single_value('GST Settings', 'gstin_email_sent_on') if last_sent and date_diff(nowdate(), last_sent) < 3: frappe.throw("Please wait 3 days before resending the reminder.") frappe.db.set_value('GST Settings', 'GST Settings', 'gstin_email_sent_on', nowdate()) # enqueue if large number of customers, suppliser frappe.enqueue('erpnext.regional.doctype.gst_settings.gst_settings.send_gstin_reminder_to_all_parties') frappe.msgprint('Email Reminders will be sent to all parties with email contacts')
def make_depreciation_entry(asset_name, date=None): frappe.has_permission("Journal Entry", throw=True) if not date: date = today() asset = frappe.get_doc("Asset", asset_name) fixed_asset_account, accumulated_depreciation_account, depreciation_expense_account = get_depreciation_accounts( asset ) depreciation_cost_center = frappe.db.get_value("Company", asset.company, "depreciation_cost_center") for d in asset.get("schedules"): if not d.journal_entry and getdate(d.schedule_date) <= getdate(date): je = frappe.new_doc("Journal Entry") je.voucher_type = "Depreciation Entry" je.posting_date = d.schedule_date je.company = asset.company je.remark = "Depreciation Entry against {0} worth {1}".format(asset_name, d.depreciation_amount) je.append( "accounts", { "account": accumulated_depreciation_account, "credit_in_account_currency": d.depreciation_amount, "reference_type": "Asset", "reference_name": asset.name, }, ) je.append( "accounts", { "account": depreciation_expense_account, "debit_in_account_currency": d.depreciation_amount, "reference_type": "Asset", "reference_name": asset.name, "cost_center": depreciation_cost_center, }, ) je.flags.ignore_permissions = True je.submit() d.db_set("journal_entry", je.name) asset.value_after_depreciation -= d.depreciation_amount asset.db_set("value_after_depreciation", asset.value_after_depreciation) asset.set_status() return asset
def make_default(name): frappe.has_permission("Print Format", "write") print_format = frappe.get_doc("Print Format", name) frappe.make_property_setter({ 'doctype_or_field': "DocType", 'doctype': print_format.doc_type, 'property': "default_print_format", 'value': name, }) frappe.msgprint(frappe._("Done"))
def sync(self): """Create and execute Data Migration Run for GCalendar Sync plan""" frappe.has_permission('GCalendar Settings', throw=True) accounts = frappe.get_all("GCalendar Account", filters={'enabled': 1}) queued_jobs = get_jobs(site=frappe.local.site, key='job_name')[frappe.local.site] for account in accounts: job_name = 'google_calendar_sync|{0}'.format(account.name) if job_name not in queued_jobs: frappe.enqueue('frappe.integrations.doctype.gcalendar_settings.gcalendar_settings.run_sync', queue='long', timeout=1500, job_name=job_name, account=account) time.sleep(5)
def can_subscribe_doc(doctype, docname, sid): from frappe.sessions import Session from frappe.exceptions import PermissionError session = Session(None).get_session_data() if not frappe.has_permission(user=session.user, doctype=doctype, doc=docname, ptype='read'): raise PermissionError() return True
def execute(self, query=None, filters=None, fields=None, or_filters=None, docstatus=None, group_by=None, order_by=None, limit_start=0, limit_page_length=20, as_list=False, with_childnames=False, debug=False, ignore_permissions=False, user=None): if not ignore_permissions and not frappe.has_permission(self.doctype, "read", user=user): raise frappe.PermissionError, self.doctype if fields: self.fields = fields self.filters = filters or [] self.or_filters = or_filters or [] self.docstatus = docstatus or [] self.group_by = group_by self.order_by = order_by self.limit_start = limit_start self.limit_page_length = limit_page_length self.with_childnames = with_childnames self.debug = debug self.as_list = as_list self.ignore_permissions = ignore_permissions self.user = user or frappe.session.user if query: return self.run_custom_query(query) else: return self.build_and_run()
def _get_party_details(party=None, account=None, party_type="Customer", company=None, posting_date=None, price_list=None, currency=None, doctype=None, ignore_permissions=False): out = frappe._dict(set_account_and_due_date(party, account, party_type, company, posting_date, doctype)) party = out[party_type.lower()] if not ignore_permissions and not frappe.has_permission(party_type, "read", party): frappe.throw(_("Not permitted"), frappe.PermissionError) party = frappe.get_doc(party_type, party) set_address_details(out, party, party_type) set_contact_details(out, party, party_type) set_other_values(out, party, party_type) set_price_list(out, party, party_type, price_list) out["taxes_and_charges"] = set_taxes(party.name, party_type, posting_date, company, out.customer_group, out.supplier_type) if not out.get("currency"): out["currency"] = currency # sales team if party_type=="Customer": out["sales_team"] = [{ "sales_person": d.sales_person, "allocated_percentage": d.allocated_percentage or None } for d in party.get("sales_team")] return out
def stop_or_unstop_sales_orders(names, status): if not frappe.has_permission("Sales Order", "write"): frappe.throw(_("Not permitted"), frappe.PermissionError) names = json.loads(names) for name in names: so = frappe.get_doc("Sales Order", name) if so.docstatus == 1: if status=="Stop": if so.status not in ("Stopped", "Cancelled") and (so.per_delivered < 100 or so.per_billed < 100): so.stop_sales_order() else: if so.status == "Stopped": so.unstop_sales_order() frappe.local.message_log = [] def before_recurring(self): super(SalesOrder, self).before_recurring() for field in ("delivery_status", "per_delivered", "billing_status", "per_billed"): self.set(field, None) for d in self.get("items"): for field in ("delivered_qty", "billed_amt", "planned_qty", "prevdoc_docname"): d.set(field, None)
def get_account_balance_and_party_type(account, date, company, debit=None, credit=None, exchange_rate=None): """Returns dict of account balance and party type to be set in Journal Entry on selection of account.""" if not frappe.has_permission("Account"): frappe.msgprint(_("No Permission"), raise_exception=1) company_currency = get_company_currency(company) account_details = frappe.db.get_value("Account", account, ["account_type", "account_currency"], as_dict=1) if account_details.account_type == "Receivable": party_type = "Customer" elif account_details.account_type == "Payable": party_type = "Supplier" else: party_type = "" grid_values = { "balance": get_balance_on(account, date), "party_type": party_type, "account_type": account_details.account_type, "account_currency": account_details.account_currency or company_currency, "exchange_rate": get_exchange_rate(account, account_details.account_currency, company, debit=debit, credit=credit, exchange_rate=exchange_rate) } # un-set party if not party type if not party_type: grid_values["party"] = "" return grid_values
def get_account_balance_and_party_type(account, date, company, debit=None, credit=None, exchange_rate=None): """Returns dict of account balance and party type to be set in Journal Entry on selection of account.""" if not frappe.has_permission("Account"): frappe.msgprint(_("No Permission"), raise_exception=1) company_currency = erpnext.get_company_currency(company) account_details = frappe.db.get_value("Account", account, ["account_type", "account_currency"], as_dict=1) if not account_details: return if account_details.account_type == "Receivable": party_type = "Customer" elif account_details.account_type == "Payable": party_type = "Supplier" else: party_type = "" grid_values = { "balance": get_balance_on(account, date), "party_type": party_type, "account_type": account_details.account_type, "account_currency": account_details.account_currency or company_currency, # The date used to retreive the exchange rate here is the date passed in # as an argument to this function. It is assumed to be the date on which the balance is sought "exchange_rate": get_exchange_rate(date, account, account_details.account_currency, company, debit=debit, credit=credit, exchange_rate=exchange_rate) } # un-set party if not party type if not party_type: grid_values["party"] = "" return grid_values
def upload(): if not frappe.has_permission("BRS Entries", "create"): raise frappe.PermissionError from frappe.utils.csvutils import read_csv_content_from_uploaded_file from frappe.modules import scrub rows = read_csv_content_from_uploaded_file() rows = filter(lambda x: x and any(x), rows) if not rows: msg = [_("Please select a csv file")] return {"messages": msg, "error": msg} #Columns located at 4th row columns = [scrub(f) for f in rows[2]] ret = [] error = False from frappe.utils.csvutils import check_record, import_doc for i, row in enumerate(rows[3:]): if not row: continue row_idx = i + 3 d = frappe._dict(zip(columns, row)) d["doctype"] = "BRS Entries" try: check_record(d) ret.append(import_doc(d, "BRS Entries", 1, row_idx, submit=True)) except Exception, e: error = True ret.append('Error for row (#%d) %s : %s' % (row_idx, len(row)>1 and row[1] or "", cstr(e))) frappe.errprint(frappe.get_traceback())
def get_events(start, end, filters=None): from frappe.desk.reportview import build_match_conditions if not frappe.has_permission("Task"): frappe.msgprint(_("No Permission"), raise_exception=1) conditions = build_match_conditions("Task") conditions = conditions and (" and " + conditions) or "" if filters: filters = json.loads(filters) for key in filters: if filters[key]: conditions += " and " + key + ' = "' + filters[key].replace('"', '\"') + '"' data = frappe.db.sql("""select name, exp_start_date, exp_end_date, subject, status, project from `tabTask` where ((ifnull(exp_start_date, '0000-00-00')!= '0000-00-00') \ and (exp_start_date between %(start)s and %(end)s) \ or ((ifnull(exp_start_date, '0000-00-00')!= '0000-00-00') \ and exp_end_date between %(start)s and %(end)s)) {conditions}""".format(conditions=conditions), { "start": start, "end": end }, as_dict=True, update={"allDay": 0}) return data
def get_value(doctype, fieldname, filters=None, as_dict=True, debug=False, parent=None): '''Returns a value form a document :param doctype: DocType to be queried :param fieldname: Field to be returned (default `name`) :param filters: dict or string for identifying the record''' if frappe.is_table(doctype): check_parent_permission(parent, doctype) if not frappe.has_permission(doctype): frappe.throw(_("No permission for {0}".format(doctype)), frappe.PermissionError) try: filters = json.loads(filters) if isinstance(filters, (integer_types, float)): filters = frappe.as_unicode(filters) except (TypeError, ValueError): # filters are not passesd, not json pass try: fieldname = json.loads(fieldname) except (TypeError, ValueError): # name passed, not json pass # check whether the used filters were really parseable and usable # and did not just result in an empty string or dict if not filters: filters = None return frappe.db.get_value(doctype, filters, fieldname, as_dict=as_dict, debug=debug)
def get_reply(self): if self.startswith('where is', 'find item', 'locate'): if not frappe.has_permission('Warehouse'): raise frappe.PermissionError item = '%{0}%'.format(self.strip_words(self.query, 'where is', 'find item', 'locate')) items = frappe.db.sql('''select name from `tabItem` where item_code like %(txt)s or item_name like %(txt)s or description like %(txt)s''', dict(txt=item)) if items: out = [] warehouses = frappe.get_all("Warehouse") for item in items: found = False for warehouse in warehouses: qty = frappe.db.get_value("Bin", {'item_code': item[0], 'warehouse': warehouse.name}, 'actual_qty') if qty: out.append(_('{0} units of [{1}](#Form/Item/{1}) found in [{2}](#Form/Warehouse/{2})').format(qty, item[0], warehouse.name)) found = True if not found: out.append(_('[{0}](#Form/Item/{0}) is out of stock').format(item[0])) return "\n\n".join(out) else: return _("Did not find any item called {0}".format(item))
def get_event_conditions(doctype, filters=None): """Returns SQL conditions with user permissions and filters for event queries""" from frappe.desk.reportview import get_filters_cond if not frappe.has_permission(doctype): frappe.throw(_("Not Permitted"), frappe.PermissionError) return get_filters_cond(doctype, filters, [], with_match_conditions = True)
def insert_item_price(args): """Insert Item Price if Price List and Price List Rate are specified and currency is the same""" if frappe.db.get_value("Price List", args.price_list, "currency") == args.currency \ and cint(frappe.db.get_single_value("Stock Settings", "auto_insert_price_list_rate_if_missing")): if frappe.has_permission("Item Price", "write"): price_list_rate = args.rate / args.conversion_factor \ if args.get("conversion_factor") else args.rate item_price = frappe.get_doc({ "doctype": "Item Price", "price_list": args.price_list, "item_code": args.item_code, "currency": args.currency, "price_list_rate": price_list_rate }) name = frappe.db.get_value('Item Price', {'item_code': args.item_code, 'price_list': args.price_list, 'currency': args.currency}, 'name') if name: item_price = frappe.get_doc('Item Price', name) item_price.price_list_rate = price_list_rate item_price.save() frappe.msgprint(_("Item Price updated for {0} in Price List {1}").format(args.item_code, args.price_list)) else: item_price.insert() frappe.msgprint(_("Item Price added for {0} in Price List {1}").format(args.item_code, args.price_list))
def create_meetings(data): """ No Need to send sms,push notification and email , it should be on attendence update on every user. Need to check validation/ duplication etc """ dts=json.loads(data) qry="select user from __Auth where user='******'username'])+"' and password=password('"+cstr(dts['userpass'])+"') " valid=frappe.db.sql(qry) if not valid: return { "status":"401", "message":"User name or Password is incorrect" } if not frappe.has_permission(doctype="Attendance Record", ptype="create",user=dts['username']): return { "status":"403", "message":"You have no permission to create Meeting Attendance Record" } #return "hello" fdate=dts['from_date'].split(" ") f_date=fdate[0] tdate=dts['to_date'].split(" ") t_date=tdate[0] res=frappe.db.sql("select name from `tabAttendance Record` where (cell='%s' or church='%s') and from_date like '%s%%' and to_date like '%s%%'"%(dts['cell'],dts['church'],f_date,t_date)) if res: return { "status":"401", "message":"Attendance Record is already created for same details on same date " } if dts['from_date'] and dts['to_date']: if dts['from_date'] >= dts['to_date']: return { "status":"402", "message":"To Date should be greater than From Date..!" } #return "hello" print data obj=frappe.new_doc("Attendance Record") obj.meeting_category=dts['meeting_category'] if dts['meeting_category']=="Cell Meeting": obj.meeting_subject=dts['meeting_sub'] else: obj.meeting_sub=dts['meeting_sub'] obj.from_date=f_date obj.to_date=t_date obj.venue=dts['venue'] obj.cell=dts['cell'] obj.senior_cell=dts['senior_cell'] obj.zone=dts['zone'] obj.region=dts['region'] obj.church_group=dts['church_group'] obj.church=dts['church'] obj.pcf=dts['pcf'] obj.insert(ignore_permissions=True) print "Successfully created Cell '"+obj.name+"'" ret={ "message":"Successfully created Cell '"+obj.name+"'" } return ret
def create_senior_cells(data): """ Need to check validation/ duplication etc """ dts=json.loads(data) qry="select user from __Auth where user='******'username'])+"' and password=password('"+cstr(dts['userpass'])+"') " valid=frappe.db.sql(qry) if not valid: return { "status":"401", "message":"User name or Password is incorrect" } if not frappe.has_permission(doctype="Senior Cells", ptype="create",user=dts['username']): return { "status":"403", "message":"You have no permission to create Senior Cell" } else: obj=frappe.new_doc("Senior Cells") obj.senior_cell_name=dts['senior_cell_name'] obj.senior_cell_code=dts['senior_cell_code'] obj.meeting_location=dts['meeting_location'] obj.zone=dts['zone'] obj.region=dts['region'] obj.church_group=dts['church_group'] obj.church=dts['church'] obj.pcf=dts['pcf'] obj.contact_phone_no=dts['contact_phone_no'] obj.contact_email_id=dts['contact_email_id'] obj.insert(ignore_permissions=True) return "Successfully created senior Cell '"+obj.name+"'"
def update_event(data): """ Need to check validation/ duplication etc """ dts=json.loads(data) qry="select user from __Auth where user='******'username'])+"' and password=password('"+cstr(dts['userpass'])+"') " valid=frappe.db.sql(qry) if not valid: return { "status":"401", "message":"User name or Password is incorrect" } if not frappe.has_permission(doctype="Event", ptype="create",user=dts['username']): return { "status":"403", "message":"You have no permission to create Cell" } else: obj=frappe.get_doc("Event",dts['name']) obj.subject=dts['subject'] obj.type=dts['type'] obj.starts_on=dts['starts_on'] obj.ends_on=dts['ends_on'] obj.address=dts['address'] obj.description=dts['description'] obj.save(ignore_permissions=True) ret={ "message":"Successfully updated Event '"+obj.name+"'" } return ret
def make(doctype=None, name=None, content=None, subject=None, sent_or_received="Sent", sender=None, sender_full_name=None, recipients=None, communication_medium="Email", send_email=False, print_html=None, print_format=None, attachments='[]', send_me_a_copy=False, cc=None, bcc=None, flags=None, read_receipt=None, print_letterhead=True, email_template=None, communication_type=None, ignore_permissions=False): """Make a new communication. :param doctype: Reference DocType. :param name: Reference Document name. :param content: Communication body. :param subject: Communication subject. :param sent_or_received: Sent or Received (default **Sent**). :param sender: Communcation sender (default current user). :param recipients: Communication recipients as list. :param communication_medium: Medium of communication (default **Email**). :param send_email: Send via email (default **False**). :param print_html: HTML Print format to be sent as attachment. :param print_format: Print Format name of parent document to be sent as attachment. :param attachments: List of attachments as list of files or JSON string. :param send_me_a_copy: Send a copy to the sender (default **False**). :param email_template: Template which is used to compose mail . """ is_error_report = (doctype == "User" and name == frappe.session.user and subject == "Error Report") send_me_a_copy = cint(send_me_a_copy) if not ignore_permissions: if doctype and name and not is_error_report and not frappe.has_permission( doctype, "email", name) and not (flags or {}).get('ignore_doctype_permissions'): raise frappe.PermissionError( "You are not allowed to send emails related to: {doctype} {name}" .format(doctype=doctype, name=name)) if not sender: sender = get_formatted_email(frappe.session.user) recipients = list_to_str(recipients) if isinstance(recipients, list) else recipients cc = list_to_str(cc) if isinstance(cc, list) else cc bcc = list_to_str(bcc) if isinstance(bcc, list) else bcc comm = frappe.get_doc({ "doctype": "Communication", "subject": subject, "content": content, "sender": sender, "sender_full_name": sender_full_name, "recipients": recipients, "cc": cc or None, "bcc": bcc or None, "communication_medium": communication_medium, "sent_or_received": sent_or_received, "reference_doctype": doctype, "reference_name": name, "email_template": email_template, "message_id": get_message_id().strip(" <>"), "read_receipt": read_receipt, "has_attachment": 1 if attachments else 0, "communication_type": communication_type }).insert(ignore_permissions=True) comm.save(ignore_permissions=True) if isinstance(attachments, str): attachments = json.loads(attachments) # if not committed, delayed task doesn't find the communication if attachments: add_attachments(comm.name, attachments) if cint(send_email): if not comm.get_outgoing_email_account(): frappe.throw(msg=OUTGOING_EMAIL_ACCOUNT_MISSING, exc=frappe.OutgoingEmailError) comm.send_email(print_html=print_html, print_format=print_format, send_me_a_copy=send_me_a_copy, print_letterhead=print_letterhead) emails_not_sent_to = comm.exclude_emails_list( include_sender=send_me_a_copy) return { "name": comm.name, "emails_not_sent_to": ", ".join(emails_not_sent_to or []) }
def execute(self, query=None, fields=None, filters=None, or_filters=None, docstatus=None, group_by=None, order_by=None, limit_start=False, limit_page_length=None, as_list=False, with_childnames=False, debug=False, ignore_permissions=False, user=None, with_comment_count=False, join='left join', distinct=False, start=None, page_length=None, limit=None, ignore_ifnull=False, save_user_settings=False, save_user_settings_fields=False, update=None, add_total_row=None, user_settings=None): if not ignore_permissions and not frappe.has_permission(self.doctype, "read", user=user): frappe.flags.error_message = _('Insufficient Permission for {0}').format(frappe.bold(self.doctype)) raise frappe.PermissionError(self.doctype) # fitlers and fields swappable # its hard to remember what comes first if (isinstance(fields, dict) or (isinstance(fields, list) and fields and isinstance(fields[0], list))): # if fields is given as dict/list of list, its probably filters filters, fields = fields, filters elif fields and isinstance(filters, list) \ and len(filters) > 1 and isinstance(filters[0], string_types): # if `filters` is a list of strings, its probably fields filters, fields = fields, filters if fields: self.fields = fields else: self.fields = ["`tab{0}`.`name`".format(self.doctype)] if start: limit_start = start if page_length: limit_page_length = page_length if limit: limit_page_length = limit self.filters = filters or [] self.or_filters = or_filters or [] self.docstatus = docstatus or [] self.group_by = group_by self.order_by = order_by self.limit_start = 0 if (limit_start is False) else cint(limit_start) self.limit_page_length = cint(limit_page_length) if limit_page_length else None self.with_childnames = with_childnames self.debug = debug self.join = join self.distinct = distinct self.as_list = as_list self.ignore_ifnull = ignore_ifnull self.flags.ignore_permissions = ignore_permissions self.user = user or frappe.session.user self.update = update self.user_settings_fields = copy.deepcopy(self.fields) #self.debug = True if user_settings: self.user_settings = json.loads(user_settings) if query: result = self.run_custom_query(query) else: result = self.build_and_run() if with_comment_count and not as_list and self.doctype: self.add_comment_count(result) if save_user_settings: self.save_user_settings_fields = save_user_settings_fields self.update_user_settings() return result
def run(report_name, filters=()): report = get_report_doc(report_name) if filters and isinstance(filters, basestring): filters = json.loads(filters) if not frappe.has_permission(report.ref_doctype, "report"): frappe.msgprint( _("Must have report permission to access this report."), raise_exception=True) columns, results = [], [] if report.report_type == "Query Report": if not report.query: frappe.msgprint(_("Must specify a Query to run"), raise_exception=True) if not report.query.lower().startswith("select"): frappe.msgprint(_("Query must be a SELECT"), raise_exception=True) result = [list(t) for t in frappe.db.sql(report.query, filters)] columns = [c[0] for c in frappe.db.get_description()] else: module = report.module or frappe.db.get_value( "DocType", report.ref_doctype, "module") if report.is_standard == "Yes": method_name = get_report_module_dotted_path( module, report.name) + ".execute" columns, result = frappe.get_attr(method_name)( frappe._dict(filters)) if report.apply_user_permissions and result: result = get_filtered_data(report.ref_doctype, columns, result) if cint(report.add_total_row) and result: result = add_total_row(result, columns) #hotfix for data in report #find column first, if columns starts with: # Status, Source #then, the value need to be translated column_index = [] i = 0 for column_n in columns: if isinstance(column_n, dict) == False and isinstance(column_n, tuple) == False: if column_n.find('Status') == 0 or column_n.find( _("Status")) == 0 or column_n.find("status") == 0: column_index.append(i) if column_n.find('Source') == 0 or column_n.find( _("Source")) == 0 or column_n.find("source") == 0: column_index.append(i) if column_n.find('Gender') == 0 or column_n.find( _("Gender")) == 0 or column_n.find("gender") == 0: column_index.append(i) i = i + 1 #translate value for index in column_index: for result_row in result: if isinstance(result_row, tuple) == False and isinstance( column_n, tuple) == False: result_row[index] = _(result_row[index]) return {"result": result, "columns": columns}
def make(doctype=None, name=None, content=None, subject=None, sent_or_received="Sent", sender=None, recipients=None, communication_medium="Email", send_email=False, print_html=None, print_format=None, attachments='[]', ignore_doctype_permissions=False, send_me_a_copy=False, cc=None): """Make a new communication. :param doctype: Reference DocType. :param name: Reference Document name. :param content: Communication body. :param subject: Communication subject. :param sent_or_received: Sent or Received (default **Sent**). :param sender: Communcation sender (default current user). :param recipients: Communication recipients as list. :param communication_medium: Medium of communication (default **Email**). :param send_mail: Send via email (default **False**). :param print_html: HTML Print format to be sent as attachment. :param print_format: Print Format name of parent document to be sent as attachment. :param attachments: List of attachments as list of files or JSON string. :param send_me_a_copy: Send a copy to the sender (default **False**). """ is_error_report = (doctype == "User" and name == frappe.session.user and subject == "Error Report") if doctype and name and not is_error_report and not frappe.has_permission( doctype, "email", name) and not ignore_doctype_permissions: raise frappe.PermissionError( "You are not allowed to send emails related to: {doctype} {name}". format(doctype=doctype, name=name)) if not sender: sender = get_formatted_email(frappe.session.user) comm = frappe.get_doc({ "doctype": "Communication", "subject": subject, "content": content, "sender": sender, "recipients": recipients, "cc": cc or None, "communication_medium": communication_medium, "sent_or_received": sent_or_received, "reference_doctype": doctype, "reference_name": name }) comm.insert(ignore_permissions=True) # needed for communication.notify which uses celery delay # if not committed, delayed task doesn't find the communication frappe.db.commit() if send_email: comm.send_me_a_copy = send_me_a_copy comm.send(print_html, print_format, attachments, send_me_a_copy=send_me_a_copy) return { "name": comm.name, "emails_not_sent_to": ", ".join(comm.emails_not_sent_to) if hasattr(comm, "emails_not_sent_to") else None }
def has_permission(doc, user): return frappe.has_permission(doc.doc_type, "read", doc.doc_name, user=user)
def has_permission(doc, ptype, user): if ptype == "read" and doc.reference_doctype and doc.reference_name: if frappe.has_permission(doc.reference_doctype, ptype="read", doc=doc.reference_name): return True
def _get_party_details(party=None, account=None, party_type="Customer", company=None, posting_date=None, bill_date=None, price_list=None, currency=None, doctype=None, ignore_permissions=False, fetch_payment_terms_template=True, party_address=None, company_address=None, shipping_address=None, pos_profile=None): party_details = frappe._dict( set_account_and_due_date(party, account, party_type, company, posting_date, bill_date, doctype)) party = party_details[party_type.lower()] if not ignore_permissions and not frappe.has_permission( party_type, "read", party): frappe.throw( _("Not permitted for {0}").format(party), frappe.PermissionError) party = frappe.get_doc(party_type, party) currency = party.default_currency if party.get( "default_currency") else get_company_currency(company) party_address, shipping_address = set_address_details( party_details, party, party_type, doctype, company, party_address, company_address, shipping_address) set_contact_details(party_details, party, party_type) set_other_values(party_details, party, party_type) set_price_list(party_details, party, party_type, price_list, pos_profile) party_details["tax_category"] = get_address_tax_category( party.get("tax_category"), party_address, shipping_address if party_type != "Supplier" else party_address) if not party_details.get("taxes_and_charges"): party_details["taxes_and_charges"] = set_taxes( party.name, party_type, posting_date, company, customer_group=party_details.customer_group, supplier_group=party_details.supplier_group, tax_category=party_details.tax_category, billing_address=party_address, shipping_address=shipping_address) if fetch_payment_terms_template: party_details["payment_terms_template"] = get_pyt_term_template( party.name, party_type, company) if not party_details.get("currency"): party_details["currency"] = currency # sales team if party_type == "Customer": party_details["sales_team"] = [{ "sales_person": d.sales_person, "allocated_percentage": d.allocated_percentage or None } for d in party.get("sales_team")] # supplier tax withholding category if party_type == "Supplier" and party: party_details["supplier_tds"] = frappe.get_value( party_type, party.name, "tax_withholding_category") return party_details
def check_share_permission(doctype, name): """Check if the user can share with other users""" if not frappe.has_permission(doctype, ptype="share", doc=name): frappe.throw( _("No permission to {0} {1} {2}".format("share", doctype, name)), frappe.PermissionError)
def validate_print_permission(doc): for ptype in ("read", "print"): if not frappe.has_permission(doc.doctype, ptype, doc): raise frappe.PermissionError(_("No {0} permission").format(ptype))
def get_tagged_docs(doctype, tag): frappe.has_permission(doctype, throw=True) return frappe.db.sql("""SELECT name FROM `tab{0}` WHERE _user_tags LIKE '%{1}%'""".format(doctype, tag))
def test_allowed_public(self): frappe.set_user(self.test_user) doc = frappe.get_doc( "Event", frappe.db.get_value("Event", {"subject": "_Test Event 1"})) self.assertTrue(frappe.has_permission("Event", doc=doc))
def get_single_value(doctype, field): if not frappe.has_permission(doctype): frappe.throw(_("No permission for {0}").format(doctype), frappe.PermissionError) value = frappe.db.get_single_value(doctype, field) return value
def get_open_count(doctype, name, items=[]): '''Get open count for given transactions and filters :param doctype: Reference DocType :param name: Reference Name :param transactions: List of transactions (json/dict) :param filters: optional filters (json/list)''' if frappe.flags.in_migrate or frappe.flags.in_install: return {"count": []} frappe.has_permission(doc=frappe.get_doc(doctype, name), throw=True) meta = frappe.get_meta(doctype) links = meta.get_dashboard_data() # compile all items in a list if not items: for group in links.transactions: items.extend(group.get("items")) if not isinstance(items, list): items = json.loads(items) out = [] for d in items: if d in links.get("internal_links", {}): # internal link continue filters = get_filters_for(d) fieldname = links.get("non_standard_fieldnames", {}).get(d, links.fieldname) data = {"name": d} if filters: # get the fieldname for the current document # we only need open documents related to the current document filters[fieldname] = name total = len( frappe.get_all(d, fields="name", filters=filters, limit=100, distinct=True, ignore_ifnull=True)) data["open_count"] = total total = len( frappe.get_all(d, fields="name", filters={fieldname: name}, limit=100, distinct=True, ignore_ifnull=True)) data["count"] = total out.append(data) out = { "count": out, } module = frappe.get_meta_module(doctype) if hasattr(module, "get_timeline_data"): out["timeline_data"] = module.get_timeline_data(doctype, name) return out
reference_doctype=Service Car Booking.doctype, reference_name=Service Car Booking.name, as_bulk=True ) Service Car Booking.status = "Invitation Sent" Service Car Booking.save() frappe.msgprint(_("Invitation Sent")) else: frappe.msgprint(_("Service Car Booking Status must be 'Planned'")) @frappe.whitelist() def get_Service Car Bookings(start, end): if not frappe.has_permission("Service Car Booking", "read"): raise frappe.PermissionError return frappe.db.sql("""select timestamp(`date`, from_time) as start, timestamp(`date`, to_time) as end, name, title, status, 0 as all_day from `tabService Car Booking` where `date` between %(start)s and %(end)s""", { "start": start, "end": end }, as_dict=True)
def has_permission(doc): return frappe.has_permission(doc.doc_type, "read", doc.doc_name)
def test_allowed_private_if_in_event_user(self): frappe.set_user("*****@*****.**") doc = frappe.doc("Event", frappe.db.get_value("Event", {"subject":"_Test Event 3"})) self.assertTrue(frappe.has_permission("Event", refdoc=doc))
def upload(): if not frappe.has_permission("Shift Schedule", "create"): raise frappe.PermissionError print("in upload\n\n") from frappe.utils.csvutils import read_csv_content_from_uploaded_file from frappe.modules import scrub rows = read_csv_content_from_uploaded_file() rows = filter(lambda x: x and any(x), rows) if not rows: msg = [_("Please select a csv file")] return {"messages": msg, "error": msg} columns = [] # columns = [scrub(f) for f in rows[1]] columns.append("name") # columns[1] = "date" ret = [] error = False from frappe.utils.csvutils import check_record, import_doc for i, row in enumerate(rows[4:]): print("in for loop\n\n") print("row[1]", row[1]) if not row: continue row_idx = i + 3 d = frappe._dict(zip(columns, row)) d["doctype"] = "Shift Schedule" d["employee"] = row[1] d["store"] = row[3] # d["attendance_date"] = rows[3][4] print("row\n") print(row) new_date_list = [] new_shift_time_list = [] print("new logic\n") for i in rows[3]: new_date_list.append(i) new_date_list = new_date_list[4:] new_shift_time_list = row[4:] print("\n new new_date_list", new_date_list) print("\n new new_shift_time_list", new_shift_time_list) print(len(new_shift_time_list), "new_shift_time_list\n") # print(row[1]) # length_of_dates=len(new_shift_time_list) length_of_dates = 8 for i in range(length_of_dates - 1): print("\n", i) print(new_shift_time_list[i]) print(new_date_list[i]) d["attendance_date"] = new_date_list[i] d["shift_time"] = new_shift_time_list[i] import datetime # new_date = datetime.datetime.strptime(row[11],'%d-%b-%y').strftime('%d-%m-%Y') # d["date"] = new_date if d.name: d["docstatus"] = frappe.db.get_value("Shift Schedule", d.name, "docstatus") try: check_record(d) ret.append( import_doc(d, "Shift Schedule", 1, row_idx, submit=True)) except Exception, e: error = True ret.append('Error for row (#%d) %s : %s' % (row_idx, len(row) > 1 and row[1] or "", cstr(e))) frappe.errprint(frappe.get_traceback())
def append_table(self, table_name): self.tables.append(table_name) doctype = table_name[4:-1] if (not self.flags.ignore_permissions) and ( not frappe.has_permission(doctype)): raise frappe.PermissionError, doctype
def get_mapped_doclist(from_doctype, from_docname, table_maps, target_doclist=None, postprocess=None, ignore_permissions=False): if target_doclist is None: target_doclist = [] if isinstance(target_doclist, basestring): target_doclist = json.loads(target_doclist) source = frappe.bean(from_doctype, from_docname) if not ignore_permissions and not frappe.has_permission(from_doctype, "read", source.doc): frappe.msgprint("No Permission", raise_exception=frappe.PermissionError) source_meta = frappe.get_doctype(from_doctype) target_meta = frappe.get_doctype(table_maps[from_doctype]["doctype"]) # main if target_doclist: if isinstance(target_doclist[0], dict): target_doc = frappe.doc(fielddata=target_doclist[0]) else: target_doc = target_doclist[0] else: target_doc = frappe.new_doc(table_maps[from_doctype]["doctype"]) map_doc(source.doc, target_doc, table_maps[source.doc.doctype], source_meta, target_meta) if target_doclist: target_doclist[0] = target_doc else: target_doclist = [target_doc] target_doclist = frappe.doclist(target_doclist) row_exists_for_parentfield = {} # children for source_d in source.doclist[1:]: table_map = table_maps.get(source_d.doctype) if table_map: if "condition" in table_map: if not table_map["condition"](source_d): continue target_doctype = table_map["doctype"] parentfield = target_meta.get({ "parent": target_doc.doctype, "doctype": "DocField", "fieldtype": "Table", "options": target_doctype })[0].fieldname # does row exist for a parentfield? if parentfield not in row_exists_for_parentfield: row_exists_for_parentfield[parentfield] = True if \ frappe.doclist(target_doclist).get({"parentfield": parentfield}) else False if table_map.get("add_if_empty") and row_exists_for_parentfield.get(parentfield): continue target_d = frappe.new_doc(target_doctype, target_doc, parentfield) map_doc(source_d, target_d, table_map, source_meta, target_meta, source.doclist[0]) target_d.idx = None target_doclist.append(target_d) target_doclist = frappe.doclist(target_doclist) if postprocess: new_target_doclist = postprocess(source, target_doclist) if new_target_doclist: target_doclist = new_target_doclist return target_doclist
def execute(self, fields=None, filters=None, or_filters=None, docstatus=None, group_by=None, order_by=None, limit_start=False, limit_page_length=None, as_list=False, with_childnames=False, debug=False, ignore_permissions=False, user=None, with_comment_count=False, join='left join', distinct=False, start=None, page_length=None, limit=None, ignore_ifnull=False, save_user_settings=False, save_user_settings_fields=False, update=None, add_total_row=None, user_settings=None, reference_doctype=None, return_query=False, strict=True, pluck=None, ignore_ddl=False): if not ignore_permissions and \ not frappe.has_permission(self.doctype, "select", user=user) and \ not frappe.has_permission(self.doctype, "read", user=user): frappe.flags.error_message = _( 'Insufficient Permission for {0}').format( frappe.bold(self.doctype)) raise frappe.PermissionError(self.doctype) # filters and fields swappable # its hard to remember what comes first if (isinstance(fields, dict) or (isinstance(fields, list) and fields and isinstance(fields[0], list))): # if fields is given as dict/list of list, its probably filters filters, fields = fields, filters elif fields and isinstance(filters, list) \ and len(filters) > 1 and isinstance(filters[0], string_types): # if `filters` is a list of strings, its probably fields filters, fields = fields, filters if fields: self.fields = fields else: if pluck: self.fields = ["`tab{0}`.`{1}`".format(self.doctype, pluck)] else: self.fields = ["`tab{0}`.`name`".format(self.doctype)] if start: limit_start = start if page_length: limit_page_length = page_length if limit: limit_page_length = limit self.filters = filters or [] self.or_filters = or_filters or [] self.docstatus = docstatus or [] self.group_by = group_by self.order_by = order_by self.limit_start = 0 if (limit_start is False) else cint(limit_start) self.limit_page_length = cint( limit_page_length) if limit_page_length else None self.with_childnames = with_childnames self.debug = debug self.join = join self.distinct = distinct self.as_list = as_list self.ignore_ifnull = ignore_ifnull self.flags.ignore_permissions = ignore_permissions self.user = user or frappe.session.user self.update = update self.user_settings_fields = copy.deepcopy(self.fields) self.return_query = return_query self.strict = strict self.ignore_ddl = ignore_ddl # for contextual user permission check # to determine which user permission is applicable on link field of specific doctype self.reference_doctype = reference_doctype or self.doctype if user_settings: self.user_settings = json.loads(user_settings) self.columns = self.get_table_columns() # no table & ignore_ddl, return if not self.columns: return [] result = self.build_and_run() if return_query: return result if with_comment_count and not as_list and self.doctype: self.add_comment_count(result) if save_user_settings: self.save_user_settings_fields = save_user_settings_fields self.update_user_settings() if pluck: return [d[pluck] for d in result] return result
def sync(site_id=None): """ Pulls the latest orders from eBay. Creates Sales Invoices for sold items. By default (site_id = None or -1), checks orders from all eBay sites. If site_id is specified, only orders from that site are used. We loop over each order in turn. First we extract customer details from eBay. If the customer does not exist, we then create a Customer. We update the Customer if it already exists. We create an Address for this customer, if one does not already exist, and link it to the Customer. Then we extract the order information from eBay, and create an eBay Order if it does not already exist. Finally we create or update a Sales Invoice based on the eBay transaction. This is only created if the order is completed (i.e. paid). If we raise an ErpnextEbaySyncError during processing of an order, then we rollback the database and continue to the next order. If a more serious exception occurs, then we rollback the database but we only continue if continue_on_error is true. """ if site_id is None or int(site_id) == -1: ebay_site_id = None else: site_id = int(site_id) ebay_site_id = EBAY_TRANSACTION_SITE_IDS[site_id] # This is a whitelisted function; check permissions. if not frappe.has_permission('eBay Manager'): frappe.throw('You do not have permission to access the eBay Manager', frappe.PermissionError) frappe.msgprint('Syncing eBay orders...') # Load orders from Ebay orders, num_days = get_orders(order_status='Completed') # Create a synchronization log log_dict = {"doctype": "eBay sync log", "ebay_sync_datetime": datetime.datetime.now(), "ebay_sync_days": num_days, "ebay_log_table": []} changes = [] msgprint_log = [] try: for order in orders: try: # Identify the eBay site on which the item was listed. try: site_id_order = order[ 'TransactionArray']['Transaction'][0]['Item']['Site'] except (KeyError, TypeError) as e: msgprint_log.append( 'WARNING: unable to identify site ID from:' + '\n{}\n{}'.format( order['TransactionArray'], str(e))) # Create/update Customer cust_details, address_details = extract_customer(order) create_customer(cust_details, address_details, changes) # Create/update eBay Order order_details = extract_order_info(order, changes) create_ebay_order(order_details, changes, order) # Create/update Sales Invoice create_sales_invoice(order_details, order, ebay_site_id, site_id_order, msgprint_log, changes) except ErpnextEbaySyncError as e: # Continue to next order frappe.db.rollback() msgprint_log.append(str(e)) print(e) except Exception as e: # Continue to next order frappe.db.rollback() err_msg = traceback.format_exc() print(err_msg) if not continue_on_error: msgprint('ORDER FAILED') raise else: msgprint_log.append('ORDER FAILED:\n{}'.format(err_msg)) finally: # Save the log, regardless of how far we got frappe.db.commit() for change in changes: log_dict['ebay_log_table'].append(change) log = frappe.get_doc(log_dict) if use_sync_log: log.insert(ignore_permissions=True) else: del log frappe.db.commit() msgprint_log.append('Finished.') msgprint(msgprint_log)
def has_permission(doctype, docname, perm_type="read"): # perm_type can be one of read, write, create, submit, cancel, report return {"has_permission": frappe.has_permission(doctype, perm_type.lower(), docname)}
def add(args=None): """add in someone's to do list args = { "assign_to": [], "doctype": , "name": , "description": , "assignment_rule": } """ if not args: args = frappe.local.form_dict users_with_duplicate_todo = [] shared_with_users = [] for assign_to in frappe.parse_json(args.get("assign_to")): filters = { "reference_type": args['doctype'], "reference_name": args['name'], "status": "Open", "owner": assign_to } if frappe.get_all("ToDo", filters=filters): users_with_duplicate_todo.append(assign_to) else: from frappe.utils import nowdate if not args.get('description'): args['description'] = _('Assignment for {0} {1}').format( args['doctype'], args['name']) d = frappe.get_doc({ "doctype": "ToDo", "owner": assign_to, "reference_type": args['doctype'], "reference_name": args['name'], "description": args.get('description'), "priority": args.get("priority", "Medium"), "status": "Open", "date": args.get('date', nowdate()), "assigned_by": args.get('assigned_by', frappe.session.user), 'assignment_rule': args.get('assignment_rule') }).insert(ignore_permissions=True) # set assigned_to if field exists if frappe.get_meta(args['doctype']).get_field("assigned_to"): frappe.db.set_value(args['doctype'], args['name'], "assigned_to", assign_to) doc = frappe.get_doc(args['doctype'], args['name']) # if assignee does not have permissions, share if not frappe.has_permission(doc=doc, user=assign_to): frappe.share.add(doc.doctype, doc.name, assign_to) shared_with_users.append(assign_to) # make this document followed by assigned user follow_document(args['doctype'], args['name'], assign_to) # notify notify_assignment(d.assigned_by, d.owner, d.reference_type, d.reference_name, action='ASSIGN', description=args.get("description")) if shared_with_users: user_list = format_message_for_assign_to(shared_with_users) frappe.msgprint( _("Shared with the following Users with Read access:{0}").format( user_list, alert=True)) if users_with_duplicate_todo: user_list = format_message_for_assign_to(users_with_duplicate_todo) frappe.msgprint( _("Already in the following Users ToDo list:{0}").format( user_list, alert=True)) return get(args)
def make_depreciation_entry(asset_name, date=None): frappe.has_permission('Journal Entry', throw=True) if not date: date = today() asset = frappe.get_doc("Asset", asset_name) fixed_asset_account, accumulated_depreciation_account, depreciation_expense_account = \ get_depreciation_accounts(asset) depreciation_cost_center, depreciation_series = frappe.get_cached_value( 'Company', asset.company, ["depreciation_cost_center", "series_for_depreciation_entry"]) depreciation_cost_center = asset.cost_center or depreciation_cost_center accounting_dimensions = get_checks_for_pl_and_bs_accounts() for d in asset.get("schedules"): if not d.journal_entry and getdate(d.schedule_date) <= getdate(date): je = frappe.new_doc("Journal Entry") je.voucher_type = "Depreciation Entry" je.naming_series = depreciation_series je.posting_date = d.schedule_date je.company = asset.company je.finance_book = d.finance_book je.remark = "Depreciation Entry against {0} worth {1}".format( asset_name, d.depreciation_amount) credit_entry = { "account": accumulated_depreciation_account, "credit_in_account_currency": d.depreciation_amount, "reference_type": "Asset", "reference_name": asset.name } debit_entry = { "account": depreciation_expense_account, "debit_in_account_currency": d.depreciation_amount, "reference_type": "Asset", "reference_name": asset.name, "cost_center": depreciation_cost_center } for dimension in accounting_dimensions: if (asset.get(dimension['fieldname']) or dimension.get('mandatory_for_bs')): credit_entry.update({ dimension['fieldname']: asset.get(dimension['fieldname']) or dimension.get('default_dimension') }) if (asset.get(dimension['fieldname']) or dimension.get('mandatory_for_pl')): debit_entry.update({ dimension['fieldname']: asset.get(dimension['fieldname']) or dimension.get('default_dimension') }) je.append("accounts", credit_entry) je.append("accounts", debit_entry) je.flags.ignore_permissions = True je.save() if not je.meta.get_workflow(): je.submit() d.db_set("journal_entry", je.name) idx = cint(d.finance_book_id) finance_books = asset.get('finance_books')[idx - 1] finance_books.value_after_depreciation -= d.depreciation_amount finance_books.db_update() asset.set_status() return asset
def make(doctype=None, name=None, content=None, subject=None, sent_or_received="Sent", sender=None, sender_full_name=None, recipients=None, communication_medium="Email", send_email=False, print_html=None, print_format=None, attachments='[]', send_me_a_copy=False, cc=None, bcc=None, flags=None, read_receipt=None): """Make a new communication. :param doctype: Reference DocType. :param name: Reference Document name. :param content: Communication body. :param subject: Communication subject. :param sent_or_received: Sent or Received (default **Sent**). :param sender: Communcation sender (default current user). :param recipients: Communication recipients as list. :param communication_medium: Medium of communication (default **Email**). :param send_mail: Send via email (default **False**). :param print_html: HTML Print format to be sent as attachment. :param print_format: Print Format name of parent document to be sent as attachment. :param attachments: List of attachments as list of files or JSON string. :param send_me_a_copy: Send a copy to the sender (default **False**). """ is_error_report = (doctype == "User" and name == frappe.session.user and subject == "Error Report") send_me_a_copy = cint(send_me_a_copy) if doctype and name and not is_error_report and not frappe.has_permission( doctype, "email", name) and not (flags or {}).get('ignore_doctype_permissions'): raise frappe.PermissionError( "You are not allowed to send emails related to: {doctype} {name}". format(doctype=doctype, name=name)) if not sender: sender = get_formatted_email(frappe.session.user) comm = frappe.get_doc({ "doctype": "Communication", "subject": subject, "content": content, "sender": sender, "sender_full_name": sender_full_name, "recipients": recipients, "cc": cc or None, "bcc": bcc or None, "communication_medium": communication_medium, "sent_or_received": sent_or_received, "reference_doctype": doctype, "reference_name": name, "message_id": get_message_id().strip(" <>"), "read_receipt": read_receipt, "has_attachment": 1 if attachments else 0 }) comm.insert(ignore_permissions=True) if not doctype: # if no reference given, then send it against the communication comm.db_set( dict(reference_doctype='Communication', reference_name=comm.name)) if isinstance(attachments, string_types): attachments = json.loads(attachments) # if not committed, delayed task doesn't find the communication if attachments: add_attachments(comm.name, attachments) frappe.db.commit() if cint(send_email): comm.send(print_html, print_format, attachments, send_me_a_copy=send_me_a_copy) return { "name": comm.name, "emails_not_sent_to": ", ".join(comm.emails_not_sent_to) if hasattr(comm, "emails_not_sent_to") else None }
def add(args=None): """add in someone's to do list args = { "assign_to": , "doctype": , "name": , "description": } """ if not args: args = frappe.local.form_dict if frappe.db.sql( """select owner from `tabToDo` where reference_type=%(doctype)s and reference_name=%(name)s and status in ("Open", "Overdue") and owner=%(assign_to)s""", args): frappe.throw(_("Already in user's To Do list"), DuplicateToDoError) else: from frappe.utils import nowdate # if args.get("re_assign"): # remove_from_todo_if_already_assigned(args['doctype'], args['name']) d = frappe.get_doc({ "doctype": "ToDo", "owner": args['assign_to'], "reference_type": args['doctype'], "reference_name": args['name'], "description": args.get('description'), "priority": args.get("priority", "Medium"), "status": "Open", "date": args.get('date', nowdate()), "assigned_by": args.get('assigned_by', frappe.session.user), }).insert(ignore_permissions=True) # set assigned_to if field exists if frappe.get_meta(args['doctype']).get_field("assigned_to"): frappe.db.set_value(args['doctype'], args['name'], "assigned_to", args['assign_to']) doc = frappe.get_doc(args['doctype'], args['name']) # if assignee does not have permissions, share if not frappe.has_permission(doc=doc, user=args['assign_to']): frappe.share.add(doc.doctype, doc.name, args['assign_to']) frappe.msgprint(_('Shared with user {0} with read access').format( args['assign_to']), alert=True) # notify notify_assignment(d.assigned_by, d.owner, d.reference_type, d.reference_name, action='ASSIGN',\ description=args.get("description"), notify=args.get('notify')) return get(args)
def generate_single_invoice(docname): doc = frappe.get_doc("Sales Invoice", docname) frappe.has_permission("Sales Invoice", doc=doc, throw=True) e_invoice = prepare_and_attach_invoice(doc, True) return e_invoice.file_url
def append_table(self, table_name): self.tables.append(table_name) doctype = table_name[4:-1] if (not self.flags.ignore_permissions) and (not frappe.has_permission(doctype)): frappe.flags.error_message = _('Insufficient Permission for {0}').format(frappe.bold(doctype)) raise frappe.PermissionError(doctype)
def test_not_allowed_private(self): frappe.set_user(self.test_user) doc = frappe.get_doc( "Event", frappe.db.get_value("Event", {"subject": "_Test Event 2"})) self.assertFalse(frappe.has_permission("Event", doc=doc))
def get_item_attribute(parent, attribute_value=''): if not frappe.has_permission("Item"): frappe.msgprint(_("No Permission"), raise_exception=1) return frappe.get_all("Item Attribute Value", fields = ["attribute_value"], filters = {'parent': parent, 'attribute_value': ("like", "%%%s%%" % attribute_value)})