def invite_guardian(guardian): guardian_doc = frappe.get_doc("Guardian", guardian) if not guardian_doc.guardian_email: frappe.throw(_("Please add an email address and try again.")) else: guardian_as_user = frappe.get_value( 'User', dict(email=guardian_doc.guardian_email)) if guardian_as_user: # Using msgprint as we do not want to throw an exception. Just informing the user already exist in the db. frappe.msgprint( _("The user {0} already exists.").format( getlink("User", guardian_as_user))) else: user = frappe.get_doc({ "doctype": "User", "first_name": guardian_doc.guardian_first_name, "last_name": guardian_doc.guardian_last_name, "email": guardian_doc.guardian_email, "mobile_no": guardian_doc.guardian_mobile_phone, "user_type": "Website User", "send_welcome_email": 1 }) user.flags.ignore_permissions = True user.add_roles("Guardian") user.save(ignore_permissions=True) update_password_link = user.reset_password() frappe.msgprint( _("User {0} created and welcomed with an email").format( getlink("User", user.name))) return user.name
def grant_dependant_access(doc, method): if doc.dependent: frappe.msgprint( _("Warning! {0} is a dependant doctype. If you wish to change access to it, remove it and add again." ).format(getlink("DocType", doc.parent))) return fields = frappe.get_meta(doc.parent).fields # console(fields) doctypes_granted_access = [] for field in fields: if field.get("fieldtype") in ["Link"]: if create_custom_docperm(field.options, doc.role, doc.parent): doctypes_granted_access += [field.options] if field.get("fieldtype") in ["Table"]: child_fields = frappe.get_meta(field.options).fields for child_field in child_fields: if child_field.get("fieldtype") in ["Link"]: if create_custom_docperm(child_field.options, doc.role, doc.parent): doctypes_granted_access += [child_field.options] if len(doctypes_granted_access) > 0: frappe.msgprint( _("Auto granted SELECT access to the following doctypes: " + str(doctypes_granted_access)))
def create_work_order_tasks(doc, method): #frappe.msgprint("This is create tasks" + doc.name) #return doc.name #frappe.msgprint(str(frappe.as_json(doc))) items = [] ##for item in doc.required_items: #frappe.msgprint(item.item_code) ##items.append(item.item_code) #frappe.msgprint(items) bom_list = [doc.bom_no] #frappe.msgprint(bom_list) #get bom of work order: bom = frappe.get_doc("BOM", doc.bom_no) #take from bom only 'services' items: if bom.items: for i in bom.items: item = frappe.get_doc("Item", i.item_code) if item.item_group == "Services": items.append(dict( item_code= i.item_code, qty = i.qty, #raw material qty has to be multiplied by bom qty stock_uom = i.uom, uom = i.uom, rate = i.rate )) # stock_qty = float(i.qty), tasks = [] for item in items: task = save_in_db_as_task(item, bom, doc.name) tasks.append(getlink("Task", task.name) + " " + str(task.subject)) frappe.msgprint(_("Task created:") + "\n <br>" + "\n <br>".join(tasks)) '''
def make_time_logs(self, open_new=False): """Capacity Planning. Plan time logs based on earliest availablity of workstation after Planned Start Date. Time logs will be created and remain in Draft mode and must be submitted before manufacturing entry can be made.""" if not self.operations: return timesheets = [] plan_days = frappe.db.get_single_value( "Manufacturing Settings", "capacity_planning_for_days") or 30 timesheet = make_timesheet(self.name, self.company) timesheet.set('time_logs', []) for i, d in enumerate(self.operations): if d.status != 'Completed': self.set_start_end_time_for_workstation(d, i) args = self.get_operations_data(d) add_timesheet_detail(timesheet, args) original_start_time = d.planned_start_time # validate operating hours if workstation [not mandatory] is specified try: timesheet.validate_time_logs() except OverlapError: if frappe.message_log: frappe.message_log.pop() timesheet.schedule_for_production_order(d.idx) except WorkstationHolidayError: if frappe.message_log: frappe.message_log.pop() timesheet.schedule_for_production_order(d.idx) from_time, to_time = self.get_start_end_time(timesheet, d.name) if date_diff(from_time, original_start_time) > cint(plan_days): frappe.throw( _("Unable to find Time Slot in the next {0} days for Operation {1}" ).format(plan_days, d.operation)) break d.planned_start_time = from_time d.planned_end_time = to_time d.db_update() if timesheet and open_new: return timesheet if timesheet and timesheet.get("time_logs"): timesheet.save() timesheets.append(getlink("Timesheet", timesheet.name)) self.planned_end_date = self.operations[-1].planned_end_time if timesheets: frappe.local.message_log = [] frappe.msgprint( _("Timesheet created:") + "\n" + "\n".join(timesheets))
def on_submit(self): self.make_gl_entries() if self.send_payment_request and self.student_email: pr = make_payment_request(dt="Fees", dn=self.name, recipient_id=self.student_email, submit_doc=True, use_dummy_message=True) frappe.msgprint(_("Payment request {0} created").format(getlink("Payment Request", pr.name)))
def validate_account_details(self): if not self.cost_center: frappe.throw(_("Cost center is required to book an expense claim")) if not self.payable_account: frappe.throw(_("Please set default payable account for the company {0}").format(getlink("Company",self.company))) if self.is_paid: if not self.mode_of_payment: frappe.throw(_("Mode of payment is required to make a payment").format(self.employee))
def invite_guardian(guardian): guardian_doc = frappe.get_doc("Guardian", guardian) if not guardian_doc.email_address: frappe.throw(_("Please set Email Address")) else: guardian_as_user = frappe.get_value('User', dict(email=guardian_doc.email_address)) if guardian_as_user: frappe.msgprint(_("User {0} already exists").format(getlink("User", guardian_as_user))) return guardian_as_user else: user = frappe.get_doc({ "doctype": "User", "first_name": guardian_doc.guardian_name, "email": guardian_doc.email_address, "user_type": "Website User", "send_welcome_email": 1 }).insert(ignore_permissions = True) frappe.msgprint(_("User {0} created").format(getlink("User", user.name))) return user.name
def make_time_logs(self, open_new=False): """Capacity Planning. Plan time logs based on earliest availablity of workstation after Planned Start Date. Time logs will be created and remain in Draft mode and must be submitted before manufacturing entry can be made.""" if not self.operations: return timesheets = [] plan_days = frappe.db.get_single_value("Manufacturing Settings", "capacity_planning_for_days") or 30 timesheet = make_timesheet(self.name, self.company) timesheet.set('time_logs', []) for i, d in enumerate(self.operations): if d.status != 'Completed': self.set_start_end_time_for_workstation(d, i) args = self.get_operations_data(d) add_timesheet_detail(timesheet, args) original_start_time = d.planned_start_time # validate operating hours if workstation [not mandatory] is specified try: timesheet.validate_time_logs() except OverlapError: if frappe.message_log: frappe.message_log.pop() timesheet.schedule_for_production_order(d.idx) except WorkstationHolidayError: if frappe.message_log: frappe.message_log.pop() timesheet.schedule_for_production_order(d.idx) from_time, to_time = self.get_start_end_time(timesheet, d.name) if date_diff(from_time, original_start_time) > plan_days: frappe.throw(_("Unable to find Time Slot in the next {0} days for Operation {1}").format(plan_days, d.operation)) break d.planned_start_time = from_time d.planned_end_time = to_time d.db_update() if timesheet and open_new: return timesheet if timesheet and timesheet.get("time_logs"): timesheet.save() timesheets.append(getlink("Timesheet", timesheet.name)) self.planned_end_date = self.operations[-1].planned_end_time if timesheets: frappe.local.message_log = [] frappe.msgprint(_("Timesheet created:") + "\n" + "\n".join(timesheets))
def validate_unique_iban(doc, method): """Bank Account IBAN should be unique.""" doctype = "Bank Account" bankAccountName = frappe.db.get_value(doctype, filters={ "iban": doc.iban, "name": ["!=", doc.name] }) if bankAccountName: frappe.throw( _("IBAN already exists in bank account: {0}").format( getlink(doctype, bankAccountName)))
def validate_duplicate(self): assessment_result = frappe.get_list("Assessment Result", filters={ "name": ("not in", [self.name]), "student": self.student, "assessment_plan": self.assessment_plan, "docstatus": ("!=", 2) }) if assessment_result: frappe.throw( _("Assessment Result record {0} already exists.").format( getlink("Assessment Result", assessment_result[0].name)))
def upload(rows = None, submit_after_import=None, ignore_encoding_errors=False, overwrite=None, ignore_links=False): """upload data""" frappe.flags.mute_emails = True # extra input params params = json.loads(frappe.form_dict.get("params") or '{}') if params.get("_submit"): submit_after_import = True if params.get("ignore_encoding_errors"): ignore_encoding_errors = True from frappe.utils.csvutils import read_csv_content_from_uploaded_file def bad_template(): frappe.throw(_("Please do not change the rows above {0}").format(data_keys.data_separator)) def check_data_length(): max_rows = 5000 if not data: frappe.throw(_("No data found")) elif len(data) > max_rows: frappe.throw(_("Only allowed {0} rows in one import").format(max_rows)) def get_start_row(): for i, row in enumerate(rows): if row and row[0]==data_keys.data_separator: return i+1 bad_template() def get_header_row(key): return get_header_row_and_idx(key)[0] def get_header_row_and_idx(key): for i, row in enumerate(header): if row and row[0]==key: return row, i return [], -1 def filter_empty_columns(columns): empty_cols = filter(lambda x: x in ("", None), columns) if empty_cols: if columns[-1*len(empty_cols):] == empty_cols: # filter empty columns if they exist at the end columns = columns[:-1*len(empty_cols)] else: frappe.msgprint(_("Please make sure that there are no empty columns in the file."), raise_exception=1) return columns def make_column_map(): doctype_row, row_idx = get_header_row_and_idx(data_keys.doctype) if row_idx == -1: # old style return dt = None for i, d in enumerate(doctype_row[1:]): if d not in ("~", "-"): if d: # value in doctype_row if doctype_row[i]==dt: # prev column is doctype (in case of parentfield) doctype_parentfield[dt] = doctype_row[i+1] else: dt = d doctypes.append(d) column_idx_to_fieldname[dt] = {} column_idx_to_fieldtype[dt] = {} if dt: column_idx_to_fieldname[dt][i+1] = rows[row_idx + 2][i+1] column_idx_to_fieldtype[dt][i+1] = rows[row_idx + 4][i+1] def get_doc(start_idx): if doctypes: doc = {} for idx in xrange(start_idx, len(rows)): if (not doc) or main_doc_empty(rows[idx]): for dt in doctypes: d = {} for column_idx in column_idx_to_fieldname[dt]: try: fieldname = column_idx_to_fieldname[dt][column_idx] fieldtype = column_idx_to_fieldtype[dt][column_idx] d[fieldname] = rows[idx][column_idx] if fieldtype in ("Int", "Check"): d[fieldname] = cint(d[fieldname]) elif fieldtype in ("Float", "Currency", "Percent"): d[fieldname] = flt(d[fieldname]) elif fieldtype == "Date": d[fieldname] = parse_date(d[fieldname]) if d[fieldname] else None except IndexError: pass # scrub quotes from name and modified if d.get("name") and d["name"].startswith('"'): d["name"] = d["name"][1:-1] if sum([0 if not val else 1 for val in d.values()]): d['doctype'] = dt if dt == doctype: doc.update(d) else: if not overwrite: d['parent'] = doc["name"] d['parenttype'] = doctype d['parentfield'] = doctype_parentfield[dt] doc.setdefault(d['parentfield'], []).append(d) else: break return doc else: doc = frappe._dict(zip(columns, rows[start_idx][1:])) doc['doctype'] = doctype return doc def main_doc_empty(row): return not (row and ((len(row) > 1 and row[1]) or (len(row) > 2 and row[2]))) # header if not rows: rows = read_csv_content_from_uploaded_file(ignore_encoding_errors) start_row = get_start_row() header = rows[:start_row] data = rows[start_row:] doctype = get_header_row(data_keys.main_table)[1] columns = filter_empty_columns(get_header_row(data_keys.columns)[1:]) doctypes = [] doctype_parentfield = {} column_idx_to_fieldname = {} column_idx_to_fieldtype = {} if submit_after_import and not cint(frappe.db.get_value("DocType", doctype, "is_submittable")): submit_after_import = False parenttype = get_header_row(data_keys.parent_table) if len(parenttype) > 1: parenttype = parenttype[1] # check permissions if not frappe.permissions.can_import(parenttype or doctype): frappe.flags.mute_emails = False return {"messages": [_("Not allowed to Import") + ": " + _(doctype)], "error": True} # allow limit rows to be uploaded check_data_length() make_column_map() frappe.db.begin() if overwrite==None: overwrite = params.get('overwrite') # delete child rows (if parenttype) parentfield = None if parenttype: parentfield = get_parent_field(doctype, parenttype) if overwrite: delete_child_rows(data, doctype) ret = [] error = False for i, row in enumerate(data): # bypass empty rows if main_doc_empty(row): continue row_idx = i + start_row doc = None doc = get_doc(row_idx) try: frappe.local.message_log = [] if parentfield: parent = frappe.get_doc(parenttype, doc["parent"]) doc = parent.append(parentfield, doc) parent.save() ret.append('Inserted row for %s at #%s' % (getlink(parenttype, doc.parent), unicode(doc.idx))) else: if overwrite and frappe.db.exists(doctype, doc["name"]): original = frappe.get_doc(doctype, doc["name"]) original.update(doc) original.ignore_links = ignore_links original.save() ret.append('Updated row (#%d) %s' % (row_idx + 1, getlink(original.doctype, original.name))) else: doc = frappe.get_doc(doc) doc.ignore_links = ignore_links doc.insert() ret.append('Inserted row (#%d) %s' % (row_idx + 1, getlink(doc.doctype, doc.name))) if submit_after_import: doc.submit() ret.append('Submitted row (#%d) %s' % (row_idx + 1, getlink(doc.doctype, doc.name))) except Exception, e: error = True if doc: frappe.errprint(doc if isinstance(doc, dict) else doc.as_dict()) err_msg = frappe.local.message_log and "\n\n".join(frappe.local.message_log) or cstr(e) ret.append('Error for row (#%d) %s : %s' % (row_idx + 1, len(row)>1 and row[1] or "", err_msg)) frappe.errprint(frappe.get_traceback())
def validate_duplicate(self): assessment_result = frappe.get_list("Assessment Result", filters={"name": ("not in", [self.name]), "student":self.student, "assessment_plan":self.assessment_plan, "docstatus":("!=", 2)}) if assessment_result: frappe.throw(_("Assessment Result record {0} already exists.".format(getlink("Assessment Result",assessment_result[0].name))))
def as_link(doctype, name): if via_console: return "{0}: {1}".format(doctype, name) else: return getlink(doctype, name)
def upload(rows=None, submit_after_import=None, ignore_encoding_errors=False, overwrite=None, ignore_links=False): """upload data""" frappe.flags.mute_emails = True # extra input params params = json.loads(frappe.form_dict.get("params") or '{}') if params.get("submit_after_import"): submit_after_import = True if params.get("ignore_encoding_errors"): ignore_encoding_errors = True from frappe.utils.csvutils import read_csv_content_from_uploaded_file def get_data_keys_definition(): return get_data_keys() def bad_template(): frappe.throw( _("Please do not change the rows above {0}").format( get_data_keys_definition().data_separator)) def check_data_length(): max_rows = 5000 if not data: frappe.throw(_("No data found")) elif len(data) > max_rows: frappe.throw( _("Only allowed {0} rows in one import").format(max_rows)) def get_start_row(): for i, row in enumerate(rows): if row and row[0] == get_data_keys_definition().data_separator: return i + 1 bad_template() def get_header_row(key): return get_header_row_and_idx(key)[0] def get_header_row_and_idx(key): for i, row in enumerate(header): if row and row[0] == key: return row, i return [], -1 def filter_empty_columns(columns): empty_cols = filter(lambda x: x in ("", None), columns) if empty_cols: if columns[-1 * len(empty_cols):] == empty_cols: # filter empty columns if they exist at the end columns = columns[:-1 * len(empty_cols)] else: frappe.msgprint(_( "Please make sure that there are no empty columns in the file." ), raise_exception=1) return columns def make_column_map(): doctype_row, row_idx = get_header_row_and_idx( get_data_keys_definition().doctype) if row_idx == -1: # old style return dt = None for i, d in enumerate(doctype_row[1:]): if d not in ("~", "-"): if d: # value in doctype_row if doctype_row[i] == dt: # prev column is doctype (in case of parentfield) doctype_parentfield[dt] = doctype_row[i + 1] else: dt = d doctypes.append(d) column_idx_to_fieldname[dt] = {} column_idx_to_fieldtype[dt] = {} if dt: column_idx_to_fieldname[dt][i + 1] = rows[row_idx + 2][i + 1] column_idx_to_fieldtype[dt][i + 1] = rows[row_idx + 4][i + 1] def get_doc(start_idx): if doctypes: doc = {} for idx in xrange(start_idx, len(rows)): if (not doc) or main_doc_empty(rows[idx]): for dt in doctypes: d = {} for column_idx in column_idx_to_fieldname[dt]: try: fieldname = column_idx_to_fieldname[dt][ column_idx] fieldtype = column_idx_to_fieldtype[dt][ column_idx] d[fieldname] = rows[idx][column_idx] if fieldtype in ("Int", "Check"): d[fieldname] = cint(d[fieldname]) elif fieldtype in ("Float", "Currency", "Percent"): d[fieldname] = flt(d[fieldname]) elif fieldtype == "Date": d[fieldname] = parse_date( d[fieldname]) if d[fieldname] else None except IndexError: pass # scrub quotes from name and modified if d.get("name") and d["name"].startswith('"'): d["name"] = d["name"][1:-1] if sum([0 if not val else 1 for val in d.values()]): d['doctype'] = dt if dt == doctype: doc.update(d) else: if not overwrite: d['parent'] = doc["name"] d['parenttype'] = doctype d['parentfield'] = doctype_parentfield[dt] doc.setdefault(d['parentfield'], []).append(d) else: break return doc else: doc = frappe._dict(zip(columns, rows[start_idx][1:])) doc['doctype'] = doctype return doc def main_doc_empty(row): return not (row and ((len(row) > 1 and row[1]) or (len(row) > 2 and row[2]))) # header if not rows: rows = read_csv_content_from_uploaded_file(ignore_encoding_errors) start_row = get_start_row() header = rows[:start_row] data = rows[start_row:] doctype = get_header_row(get_data_keys_definition().main_table)[1] columns = filter_empty_columns( get_header_row(get_data_keys_definition().columns)[1:]) doctypes = [] doctype_parentfield = {} column_idx_to_fieldname = {} column_idx_to_fieldtype = {} if submit_after_import and not cint( frappe.db.get_value("DocType", doctype, "is_submittable")): submit_after_import = False parenttype = get_header_row(get_data_keys_definition().parent_table) if len(parenttype) > 1: parenttype = parenttype[1] # check permissions if not frappe.permissions.can_import(parenttype or doctype): frappe.flags.mute_emails = False return { "messages": [_("Not allowed to Import") + ": " + _(doctype)], "error": True } # allow limit rows to be uploaded check_data_length() make_column_map() frappe.db.begin() if overwrite == None: overwrite = params.get('overwrite') # delete child rows (if parenttype) parentfield = None if parenttype: parentfield = get_parent_field(doctype, parenttype) if overwrite: delete_child_rows(data, doctype) ret = [] error = False for i, row in enumerate(data): # bypass empty rows if main_doc_empty(row): continue row_idx = i + start_row doc = None doc = get_doc(row_idx) try: frappe.local.message_log = [] if parentfield: parent = frappe.get_doc(parenttype, doc["parent"]) doc = parent.append(parentfield, doc) parent.save() ret.append('Inserted row for %s at #%s' % (getlink(parenttype, doc.parent), unicode(doc.idx))) else: if overwrite and doc["name"] and frappe.db.exists( doctype, doc["name"]): original = frappe.get_doc(doctype, doc["name"]) original.update(doc) original.ignore_links = ignore_links original.save() ret.append('Updated row (#%d) %s' % (row_idx + 1, getlink(original.doctype, original.name))) else: doc = frappe.get_doc(doc) doc.ignore_links = ignore_links doc.insert() ret.append('Inserted row (#%d) %s' % (row_idx + 1, getlink(doc.doctype, doc.name))) if submit_after_import: doc.submit() ret.append('Submitted row (#%d) %s' % (row_idx + 1, getlink(doc.doctype, doc.name))) except Exception, e: error = True if doc: frappe.errprint( doc if isinstance(doc, dict) else doc.as_dict()) err_msg = frappe.local.message_log and "\n\n".join( frappe.local.message_log) or cstr(e) ret.append('Error for row (#%d) %s : %s' % (row_idx + 1, len(row) > 1 and row[1] or "", err_msg)) frappe.errprint(frappe.get_traceback())
def validate_account_details(self): if not self.cost_center: frappe.throw(_("Cost center is required to book an expense claim")) if not self.payable_account: frappe.throw(_("Please set default payable account for the company {0}").format(getlink("Company",self.company)))