+ {% if (data.owner==data.comment_docname
+ && data.parenttype!="Assignment") { %}
+
diff --git a/frappe/desk/page/setup_wizard/__init__.py b/frappe/desk/page/setup_wizard/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/frappe/desk/page/setup_wizard/setup_wizard.css b/frappe/desk/page/setup_wizard/setup_wizard.css
new file mode 100644
index 0000000000..41eef343c0
--- /dev/null
+++ b/frappe/desk/page/setup_wizard/setup_wizard.css
@@ -0,0 +1,70 @@
+.setup-wizard-slide {
+ padding-left: 0px;
+ padding-right: 0px;
+}
+
+@media (min-width: 768px) {
+ .setup-wizard-slide.single-column {
+ max-width: 500px;
+ }
+
+ .setup-wizard-slide.two-column {
+ max-width: 768px;
+ }
+}
+
+.setup-wizard-slide .lead {
+ margin-bottom: 10px;
+}
+
+.setup-wizard-slide .form {
+ margin-top: 20px;
+ border: 1px solid #d1d8dd;
+ box-shadow: 0px 3px 5px rgba(0, 0, 0, 0.1);
+}
+
+.setup-wizard-slide .footer {
+ margin: 20px auto;
+}
+
+.setup-wizard-progress {
+ border-bottom: 1px solid #d1d8dd;
+ padding-bottom: 15px;
+ margin: -20px auto 20px;
+}
+
+.setup-wizard-slide .icon-fixed-width {
+ vertical-align: middle;
+}
+
+.setup-wizard-slide .icon-circle-blank {
+ font-size: 7px;
+}
+
+.setup-wizard-slide .icon-circle {
+ font-size: 10px;
+}
+
+.setup-wizard-slide .frappe-control[data-fieldtype="Attach Image"] {
+ text-align: center;
+}
+
+.setup-wizard-slide .missing-image,
+.setup-wizard-slide .attach-image-display {
+ display: block;
+ position: relative;
+ left: 50%;
+ transform: translate(-50%, 0);
+ -webkit-transform: translate(-50%, 0);
+}
+
+.setup-wizard-slide .missing-image .octicon {
+ position: relative;
+ top: 50%;
+ transform: translate(0px, -50%);
+ -webkit-transform: translate(0px, -50%);
+}
+
+.setup-wizard-message-image {
+ margin: 15px auto;
+}
diff --git a/frappe/desk/page/setup_wizard/setup_wizard.js b/frappe/desk/page/setup_wizard/setup_wizard.js
new file mode 100644
index 0000000000..b513dc263e
--- /dev/null
+++ b/frappe/desk/page/setup_wizard/setup_wizard.js
@@ -0,0 +1,410 @@
+frappe.provide("frappe.wiz");
+frappe.provide("frappe.wiz.events");
+
+frappe.wiz = {
+ slides: [],
+ events: {},
+ on: function(event, fn) {
+ if(!frappe.wiz.events[event]) {
+ frappe.wiz.events[event] = [];
+ }
+ frappe.wiz.events[event].push(fn);
+ },
+ add_slide: function(slide) {
+ frappe.wiz.slides.push(slide);
+ },
+ run_event: function(event) {
+ $.each(frappe.wiz.events[event] || [], function(i, fn) {
+ fn(frappe.wiz.wizard);
+ });
+ }
+}
+
+frappe.pages['setup-wizard'].on_page_load = function(wrapper) {
+ // setup page ui
+ $(".navbar:first").toggle(false);
+ $("body").css({"padding-top":"30px"});
+
+ frappe.require("/assets/frappe/css/animate.min.css");
+
+ $.each(frappe.boot.setup_wizard_requires || [], function(i, path) {
+ frappe.require(path);
+ });
+
+ frappe.wiz.run_event("before_load");
+
+ var wizard_settings = {
+ page_name: "setup-wizard",
+ parent: wrapper,
+ slides: frappe.wiz.slides,
+ title: __("Welcome")
+ }
+
+ frappe.wiz.wizard = new frappe.wiz.Wizard(wizard_settings);
+
+ frappe.wiz.run_event("after_load");
+}
+
+frappe.pages['setup-wizard'].on_page_show = function(wrapper) {
+ if(frappe.get_route()[1]) {
+ frappe.wiz.wizard.show(frappe.get_route()[1]);
+ }
+}
+
+frappe.wiz.Wizard = Class.extend({
+ init: function(opts) {
+ $.extend(this, opts);
+ this.make();
+ this.slides;
+ this.slide_dict = {};
+ this.welcomed = true;
+ frappe.set_route("setup-wizard/0");
+ },
+ make: function() {
+ this.parent = $('
').appendTo(this.parent);
+ },
+ get_message: function(html) {
+ return $(repl('
', {html:html}))
+ },
+ show_working: function() {
+ this.hide_current_slide();
+ frappe.set_route(this.page_name);
+ this.current_slide = {"$wrapper": this.get_message(this.working_html()).appendTo(this.parent)};
+ },
+ show_complete: function() {
+ this.hide_current_slide();
+ this.current_slide = {"$wrapper": this.get_message(this.complete_html()).appendTo(this.parent)};
+ },
+ show: function(id) {
+ if(!this.welcomed) {
+ frappe.set_route(this.page_name);
+ return;
+ }
+ id = cint(id);
+ if(this.current_slide && this.current_slide.id===id)
+ return;
+ if(!this.slide_dict[id]) {
+ this.slide_dict[id] = new frappe.wiz.WizardSlide($.extend(this.slides[id], {wiz:this, id:id}));
+ this.slide_dict[id].make();
+ }
+
+ this.hide_current_slide();
+
+ this.current_slide = this.slide_dict[id];
+ this.current_slide.$wrapper.removeClass("hidden");
+ },
+ hide_current_slide: function() {
+ if(this.current_slide) {
+ this.current_slide.$wrapper.addClass("hidden");
+ this.current_slide = null;
+ }
+ },
+ get_values: function() {
+ var values = {};
+ $.each(this.slide_dict, function(id, slide) {
+ $.extend(values, slide.values)
+ })
+ return values;
+ },
+ working_html: function() {
+ var msg = $(frappe.render_template("setup_wizard_message", {
+ image: "/assets/frappe/images/ui/bubble-tea-smile.svg",
+ title: __("Setting Up"),
+ message: __('Sit tight while your system is being setup. This may take a few moments.')
+ }));
+ msg.find(".setup-wizard-message-image").addClass("animated infinite bounce");
+ return msg.html();
+ },
+
+ complete_html: function() {
+ return frappe.render_template("setup_wizard_message", {
+ image: "/assets/frappe/images/ui/bubble-tea-happy.svg",
+ title: __('Setup Complete'),
+ message: ""
+ });
+ },
+
+ on_complete: function() {
+ var me = this;
+ var values = me.get_values();
+ me.show_working();
+ return frappe.call({
+ method: "frappe.desk.page.setup_wizard.setup_wizard.setup_complete",
+ args: {args: values},
+ callback: function(r) {
+ me.show_complete();
+ if(frappe.wiz.welcome_page) {
+ localStorage.setItem("session_last_route", frappe.wiz.welcome_page);
+ }
+ setTimeout(function() {
+ window.location = "/desk";
+ }, 2000);
+ },
+ error: function(r) {
+ var d = msgprint(__("There were errors."));
+ d.custom_onhide = function() {
+ frappe.set_route(me.page_name, me.slides.length - 1);
+ };
+ }
+ });
+ }
+
+});
+
+frappe.wiz.WizardSlide = Class.extend({
+ init: function(opts) {
+ $.extend(this, opts);
+ this.$wrapper = $('
')
+ .appendTo(this.wiz.parent)
+ .attr("data-slide-id", this.id);
+ },
+ make: function() {
+ var me = this;
+ if(this.$body) this.$body.remove();
+
+ if(this.before_load) {
+ this.before_load(this);
+ }
+
+ this.$body = $(frappe.render_template("setup_wizard_page", {
+ help: __(this.help),
+ title:__(this.title),
+ main_title:__(this.wiz.title),
+ step: this.id + 1,
+ name: this.name,
+ css_class: this.css_class || "",
+ slides_count: this.wiz.slides.length
+ })).appendTo(this.$wrapper);
+
+ this.body = this.$body.find(".form")[0];
+
+ if(this.fields) {
+ this.form = new frappe.ui.FieldGroup({
+ fields: this.fields,
+ body: this.body,
+ no_submit_on_enter: true
+ });
+ this.form.make();
+ } else {
+ $(this.body).html(this.html);
+ }
+
+ if(this.id > 0) {
+ this.$prev = this.$body.find('.prev-btn').removeClass("hide")
+ .click(function() {
+ frappe.set_route(me.wiz.page_name, me.id-1 + "");
+ })
+ .css({"margin-right": "10px"});
+ }
+ if(this.id+1 < this.wiz.slides.length) {
+ this.$next = this.$body.find('.next-btn').removeClass("hide")
+ .click(function() {
+ me.values = me.form.get_values();
+ if(me.values===null)
+ return;
+ if(me.validate && !me.validate())
+ return;
+ frappe.set_route(me.wiz.page_name, me.id+1 + "");
+ })
+ } else {
+ this.$complete = this.$body.find('.complete-btn').removeClass("hide")
+ .click(function() {
+ me.values = me.form.get_values();
+ if(me.values===null)
+ return;
+ if(me.validate && !me.validate())
+ return;
+ me.wiz.on_complete(me.wiz);
+ })
+ }
+
+ if(this.onload) {
+ this.onload(this);
+ }
+
+ },
+ get_input: function(fn) {
+ return this.form.get_input(fn);
+ },
+ get_field: function(fn) {
+ return this.form.get_field(fn);
+ }
+});
+
+function load_frappe_slides() {
+ // language selection
+ frappe.wiz.welcome = {
+ name: "welcome",
+ title: __("Welcome"),
+ icon: "icon-world",
+ help: __("Let's prepare the system for first use."),
+
+ fields: [
+ { fieldname: "language", label: __("Select Your Language"), reqd:1,
+ fieldtype: "Select" },
+ ],
+
+ onload: function(slide) {
+ if (!frappe.wiz.welcome.data) {
+ frappe.wiz.welcome.load_languages(slide);
+ } else {
+ frappe.wiz.welcome.setup_fields(slide);
+ }
+ },
+
+ css_class: "single-column",
+ load_languages: function(slide) {
+ frappe.call({
+ method: "frappe.desk.page.setup_wizard.setup_wizard.load_languages",
+ callback: function(r) {
+ frappe.wiz.welcome.data = r.message;
+ frappe.wiz.welcome.setup_fields(slide);
+
+ slide.get_field("language")
+ .set_input(frappe.wiz.welcome.data.default_language || "english")
+ .trigger("change");
+
+ moment.locale("en");
+ }
+ });
+ },
+
+ setup_fields: function(slide) {
+ var select = slide.get_field("language");
+ select.df.options = frappe.wiz.welcome.data.languages;
+ select.refresh();
+ frappe.wiz.welcome.bind_events(slide);
+ },
+
+ bind_events: function(slide) {
+ slide.get_input("language").unbind("change").on("change", function() {
+ var lang = $(this).val() || "english";
+ frappe._messages = {};
+ frappe.call({
+ method: "frappe.desk.page.setup_wizard.setup_wizard.load_messages",
+ args: {
+ language: lang
+ },
+ callback: function(r) {
+ // TODO save values!
+
+ // reset all slides so that labels are translated
+ frappe.wiz.slides = [];
+ frappe.wiz.run_event("before_load");
+ frappe.wiz.wizard.slides = frappe.wiz.slides;
+ frappe.wiz.run_event("after_load");
+
+ // re-render all slides
+ $.each(slide.wiz.slide_dict, function(id, s) {
+ $.extend(s, frappe.wiz.slides[id]);
+ s.make();
+ });
+
+ // select is re-made after language change
+ var select = slide.get_field("language");
+ select.set_input(lang);
+ }
+ });
+ });
+ }
+ }
+
+ // region selection
+ frappe.wiz.region = {
+ title: __("Region"),
+ icon: "icon-flag",
+ help: __("Select your Country, Time Zone and Currency"),
+ fields: [
+ { fieldname: "country", label: __("Country"), reqd:1,
+ fieldtype: "Select" },
+ { fieldname: "timezone", label: __("Time Zone"), reqd:1,
+ fieldtype: "Select" },
+ { fieldname: "currency", label: __("Currency"), reqd:1,
+ fieldtype: "Select" },
+ ],
+
+ onload: function(slide) {
+ frappe.call({
+ method:"frappe.geo.country_info.get_country_timezone_info",
+ callback: function(data) {
+ frappe.wiz.region.data = data.message;
+ frappe.wiz.region.setup_fields(slide);
+ frappe.wiz.region.bind_events(slide);
+ }
+ });
+ },
+ css_class: "single-column",
+ setup_fields: function(slide) {
+ var data = frappe.wiz.region.data;
+
+ slide.get_input("country").empty()
+ .add_options([""].concat(keys(data.country_info).sort()));
+
+ slide.get_input("currency").empty()
+ .add_options(frappe.utils.unique([""].concat($.map(data.country_info,
+ function(opts, country) { return opts.currency; }))).sort());
+
+ slide.get_input("timezone").empty()
+ .add_options([""].concat(data.all_timezones));
+
+ if (data.default_country) {
+ slide.set_input("country", data.default_country);
+ }
+ },
+
+ bind_events: function(slide) {
+ slide.get_input("country").on("change", function() {
+ var country = slide.get_input("country").val();
+ var $timezone = slide.get_input("timezone");
+ var data = frappe.wiz.region.data;
+
+ $timezone.empty();
+
+ // add country specific timezones first
+ if(country) {
+ var timezone_list = data.country_info[country].timezones || [];
+ $timezone.add_options(timezone_list.sort());
+ slide.get_field("currency").set_input(data.country_info[country].currency);
+ slide.get_field("currency").$input.trigger("change");
+ }
+
+ // add all timezones at the end, so that user has the option to change it to any timezone
+ $timezone.add_options([""].concat(data.all_timezones));
+
+ slide.get_field("timezone").set_input($timezone.val());
+
+ // temporarily set date format
+ frappe.boot.sysdefaults.date_format = (data.country_info[country].date_format
+ || "dd-mm-yyyy");
+ });
+
+ slide.get_input("currency").on("change", function() {
+ var currency = slide.get_input("currency").val();
+ if (!currency) return;
+ frappe.model.with_doc("Currency", currency, function() {
+ frappe.provide("locals.:Currency." + currency);
+ var currency_doc = frappe.model.get_doc("Currency", currency);
+ var number_format = currency_doc.number_format;
+ if (number_format==="#.###") {
+ number_format = "#.###,##";
+ } else if (number_format==="#,###") {
+ number_format = "#,###.##"
+ }
+
+ frappe.boot.sysdefaults.number_format = number_format;
+ locals[":Currency"][currency] = $.extend({}, currency_doc);
+ });
+ });
+ }
+ };
+};
+
+frappe.wiz.on("before_load", function() {
+ load_frappe_slides();
+
+ // add welcome slide
+ frappe.wiz.add_slide(frappe.wiz.welcome);
+ frappe.wiz.add_slide(frappe.wiz.region);
+});
diff --git a/frappe/desk/page/setup_wizard/setup_wizard.json b/frappe/desk/page/setup_wizard/setup_wizard.json
new file mode 100644
index 0000000000..f18c740665
--- /dev/null
+++ b/frappe/desk/page/setup_wizard/setup_wizard.json
@@ -0,0 +1,22 @@
+{
+ "content": null,
+ "creation": "2013-10-04 13:49:33",
+ "docstatus": 0,
+ "doctype": "Page",
+ "idx": 1,
+ "modified": "2015-11-09 03:06:14.542388",
+ "modified_by": "Administrator",
+ "module": "Desk",
+ "name": "setup-wizard",
+ "owner": "Administrator",
+ "page_name": "setup-wizard",
+ "roles": [
+ {
+ "role": "System Manager"
+ }
+ ],
+ "script": null,
+ "standard": "Yes",
+ "style": null,
+ "title": "Setup Wizard"
+}
\ No newline at end of file
diff --git a/frappe/desk/page/setup_wizard/setup_wizard.py b/frappe/desk/page/setup_wizard/setup_wizard.py
new file mode 100644
index 0000000000..53c6b15826
--- /dev/null
+++ b/frappe/desk/page/setup_wizard/setup_wizard.py
@@ -0,0 +1,103 @@
+# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
+# License: See license.txt
+
+from __future__ import unicode_literals
+
+import frappe, json, os
+from frappe.utils import strip
+from frappe.translate import (set_default_language, get_dict,
+ get_lang_dict, send_translations, get_language_from_code)
+from frappe.geo.country_info import get_country_info
+
+@frappe.whitelist()
+def setup_complete(args):
+ """Calls hooks for `setup_wizard_complete`, sets home page as `desktop`
+ and clears cache. If wizard breaks, calls `setup_wizard_exception` hook"""
+ args = process_args(args)
+
+ try:
+ if args.language and args.language != "english":
+ set_default_language(args.language)
+
+ frappe.clear_cache()
+
+ # update system settings
+ update_system_settings(args)
+
+ for method in frappe.get_hooks("setup_wizard_complete"):
+ frappe.get_attr(method)(args)
+
+ frappe.db.set_default('desktop:home_page', 'desktop')
+ frappe.db.commit()
+ frappe.clear_cache()
+ except:
+ if args:
+ traceback = frappe.get_traceback()
+ for hook in frappe.get_hooks("setup_wizard_exception"):
+ frappe.get_attr(hook)(traceback, args)
+
+ raise
+
+ else:
+ for hook in frappe.get_hooks("setup_wizard_success"):
+ frappe.get_attr(hook)(args)
+
+def update_system_settings(args):
+ number_format = get_country_info(args.get("country")).get("number_format", "#,###.##")
+
+ # replace these as float number formats, as they have 0 precision
+ # and are currency number formats and not for floats
+ if number_format=="#.###":
+ number_format = "#.###,##"
+ elif number_format=="#,###":
+ number_format = "#,###.##"
+
+ system_settings = frappe.get_doc("System Settings", "System Settings")
+ system_settings.update({
+ "language": args.get("language"),
+ "time_zone": args.get("timezone"),
+ "float_precision": 3,
+ 'date_format': frappe.db.get_value("Country", args.get("country"), "date_format"),
+ 'number_format': number_format,
+ 'enable_scheduler': 1 if not frappe.flags.in_test else 0
+ })
+ system_settings.save()
+
+def process_args(args):
+ if not args:
+ args = frappe.local.form_dict
+ if isinstance(args, basestring):
+ args = json.loads(args)
+
+ args = frappe._dict(args)
+
+ # strip the whitespace
+ for key, value in args.items():
+ if isinstance(value, basestring):
+ args[key] = strip(value)
+
+ return args
+
+@frappe.whitelist()
+def load_messages(language):
+ """Load translation messages for given langauge from all `setup_wizard_requires`
+ javascript files"""
+ frappe.clear_cache()
+ set_default_language(language)
+ m = get_dict("page", "setup-wizard")
+
+ for path in frappe.get_hooks("setup_wizard_requires"):
+ # common folder `assets` served from `sites/`
+ js_file_path = os.path.abspath(frappe.get_site_path("..", *path.strip("/").split("/")))
+ m.update(get_dict("jsfile", js_file_path))
+
+ m.update(get_dict("boot"))
+ send_translations(m)
+ return frappe.local.lang
+
+@frappe.whitelist()
+def load_languages():
+ return {
+ "default_language": get_language_from_code(frappe.local.lang),
+ "languages": sorted(get_lang_dict().keys())
+ }
diff --git a/frappe/desk/page/setup_wizard/setup_wizard_message.html b/frappe/desk/page/setup_wizard/setup_wizard_message.html
new file mode 100644
index 0000000000..e2f6bbc51d
--- /dev/null
+++ b/frappe/desk/page/setup_wizard/setup_wizard_message.html
@@ -0,0 +1,7 @@
+
+
+
+
{%= title %}
+
+
{%= message %}
+
diff --git a/frappe/desk/page/setup_wizard/setup_wizard_page.html b/frappe/desk/page/setup_wizard/setup_wizard_page.html
new file mode 100644
index 0000000000..00673174ce
--- /dev/null
+++ b/frappe/desk/page/setup_wizard/setup_wizard_page.html
@@ -0,0 +1,21 @@
+
+
+
{%= title %}
+
+
+ {% if (help) { %}
{%= help %}
{% } %}
+
+
+
+
+
diff --git a/frappe/desk/query_report.py b/frappe/desk/query_report.py
index fe4d59df8d..5e12a26a30 100644
--- a/frappe/desk/query_report.py
+++ b/frappe/desk/query_report.py
@@ -11,6 +11,7 @@ from frappe.modules import scrub, get_module_path
from frappe.utils import flt, cint, get_html_format
from frappe.translate import send_translations
import frappe.desk.reportview
+from frappe.permissions import get_role_permissions
def get_report_doc(report_name):
doc = frappe.get_doc("Report", report_name)
@@ -144,20 +145,36 @@ def get_filtered_data(ref_doctype, columns, data):
linked_doctypes = get_linked_doctypes(columns, data)
match_filters_per_doctype = get_user_match_filters(linked_doctypes, ref_doctype)
shared = frappe.share.get_shared(ref_doctype)
+ columns_dict = get_columns_dict(columns)
+
+ role_permissions = get_role_permissions(frappe.get_meta(ref_doctype))
+ if_owner = role_permissions.get("if_owner", {}).get("report")
if match_filters_per_doctype:
for row in data:
- if shared and row[linked_doctypes[ref_doctype]] in shared:
+ # Why linked_doctypes.get(ref_doctype)? because if column is empty, linked_doctypes[ref_doctype] is removed
+ if linked_doctypes.get(ref_doctype) and shared and row[linked_doctypes[ref_doctype]] in shared:
result.append(row)
- elif has_match(row, linked_doctypes, match_filters_per_doctype):
+ elif has_match(row, linked_doctypes, match_filters_per_doctype, ref_doctype, if_owner, columns_dict):
result.append(row)
else:
result = list(data)
return result
-def has_match(row, linked_doctypes, doctype_match_filters):
+def has_match(row, linked_doctypes, doctype_match_filters, ref_doctype, if_owner, columns_dict):
+ """Returns True if after evaluating permissions for each linked doctype
+ - There is an owner match for the ref_doctype
+ - `and` There is a user permission match for all linked doctypes
+
+ Returns True if the row is empty
+
+ Note:
+ Each doctype could have multiple conflicting user permission doctypes.
+ Hence even if one of the sets allows a match, it is true.
+ This behavior is equivalent to the trickling of user permissions of linked doctypes to the ref doctype.
+ """
resultant_match = True
if not row:
@@ -167,20 +184,33 @@ def has_match(row, linked_doctypes, doctype_match_filters):
for doctype, filter_list in doctype_match_filters.items():
matched_for_doctype = False
- for match_filters in filter_list:
- match = True
- for dt, idx in linked_doctypes.items():
- if dt in match_filters and row[idx] not in match_filters[dt]:
- match = False
+ if doctype==ref_doctype and if_owner:
+ idx = linked_doctypes.get("User")
+ if (idx is not None
+ and row[idx]==frappe.session.user
+ and columns_dict[idx]==columns_dict.get("owner")):
+ # owner match is true
+ matched_for_doctype = True
+
+ if not matched_for_doctype:
+ for match_filters in filter_list:
+ match = True
+ for dt, idx in linked_doctypes.items():
+ # case handled above
+ if dt=="User" and columns_dict[idx]==columns_dict.get("owner"):
+ continue
+
+ if dt in match_filters and row[idx] not in match_filters[dt]:
+ match = False
+ break
+
+ # each doctype could have multiple conflicting user permission doctypes, hence using OR
+ # so that even if one of the sets allows a match, it is true
+ matched_for_doctype = matched_for_doctype or match
+
+ if matched_for_doctype:
break
- # each doctype could have multiple conflicting user permission doctypes, hence using OR
- # so that even if one of the sets allows a match, it is true
- matched_for_doctype = matched_for_doctype or match
-
- if matched_for_doctype:
- break
-
# each doctype's user permissions should match the row! hence using AND
resultant_match = resultant_match and matched_for_doctype
@@ -192,24 +222,68 @@ def has_match(row, linked_doctypes, doctype_match_filters):
def get_linked_doctypes(columns, data):
linked_doctypes = {}
- for idx, col in enumerate(columns):
- if isinstance(col, basestring):
- col = col.split(":")
- if len(col) > 1 and col[1].startswith("Link"):
- link_dt = col[1].split("/")[1]
- linked_doctypes[link_dt] = idx
+ columns_dict = get_columns_dict(columns)
- # dict
- elif col.get("fieldtype")=="Link" and col.get("options"):
- linked_doctypes[col["options"]] = col["fieldname"]
+ for idx, col in enumerate(columns):
+ df = columns_dict[idx]
+ if df.get("fieldtype")=="Link":
+ if isinstance(col, basestring):
+ linked_doctypes[df["options"]] = idx
+ else:
+ # dict
+ linked_doctypes[df["options"]] = df["fieldname"]
# remove doctype if column is empty
+ columns_with_value = []
+ for row in data:
+ if row:
+ if len(row) != len(columns_with_value):
+ if isinstance(row, (list, tuple)):
+ row = enumerate(row)
+ elif isinstance(row, dict):
+ row = row.items()
+
+ for col, val in row:
+ if val and col not in columns_with_value:
+ columns_with_value.append(col)
+
for doctype, key in linked_doctypes.items():
- if not any(d[key] for d in data if d):
+ if key not in columns_with_value:
del linked_doctypes[doctype]
return linked_doctypes
+def get_columns_dict(columns):
+ """Returns a dict with column docfield values as dict
+ The keys for the dict are both idx and fieldname,
+ so either index or fieldname can be used to search for a column's docfield properties
+ """
+ columns_dict = {}
+ for idx, col in enumerate(columns):
+ col_dict = {}
+
+ # string
+ if isinstance(col, basestring):
+ col = col.split(":")
+ if len(col) > 1:
+ if "/" in col[1]:
+ col_dict["fieldtype"], col_dict["options"] = col[1].split("/")
+ else:
+ col_dict["fieldtype"] = col[1]
+
+ col_dict["fieldname"] = frappe.scrub(col[0])
+
+ # dict
+ else:
+ col_dict.update(col)
+ if "fieldname" not in col_dict:
+ col_dict["fieldname"] = frappe.scrub(col_dict["label"])
+
+ columns_dict[idx] = col_dict
+ columns_dict[col_dict["fieldname"]] = col_dict
+
+ return columns_dict
+
def get_user_match_filters(doctypes, ref_doctype):
match_filters = {}
diff --git a/frappe/desk/reportview.py b/frappe/desk/reportview.py
index 248eb242f4..6d2a64ff3e 100644
--- a/frappe/desk/reportview.py
+++ b/frappe/desk/reportview.py
@@ -177,7 +177,11 @@ def scrub_user_tags(tagcount):
# used in building query in queries.py
def get_match_cond(doctype):
cond = DatabaseQuery(doctype).build_match_conditions()
- return (' and ' + cond) if cond else ""
+ return ((' and ' + cond) if cond else "").replace("%", "%%")
def build_match_conditions(doctype, as_condition=True):
- return DatabaseQuery(doctype).build_match_conditions(as_condition=as_condition)
+ match_conditions = DatabaseQuery(doctype).build_match_conditions(as_condition=as_condition)
+ if as_condition:
+ return match_conditions.replace("%", "%%")
+ else:
+ return match_conditions
diff --git a/frappe/desk/search.py b/frappe/desk/search.py
index a03b2352a7..c8230fe4c0 100644
--- a/frappe/desk/search.py
+++ b/frappe/desk/search.py
@@ -56,16 +56,21 @@ def search_widget(doctype, txt, query=None, searchfield=None, start=0,
filters = []
or_filters = []
+
# build from doctype
if txt:
+ search_fields = ["name"]
+ if meta.title_field:
+ search_fields.append(meta.title_field)
+
if meta.search_fields:
- for f in meta.get_search_fields():
- fmeta = meta.get_field(f.strip())
- if f == "name" or (fmeta and fmeta.fieldtype in ["Data", "Text", "Small Text", "Long Text",
- "Link", "Select", "Read Only", "Text Editor"]):
- or_filters.append([doctype, f.strip(), "like", "%{0}%".format(txt)])
- else:
- filters.append([doctype, searchfield or "name", "like", "%{0}%".format(txt)])
+ search_fields.extend(meta.get_search_fields())
+
+ for f in search_fields:
+ fmeta = meta.get_field(f.strip())
+ if f == "name" or (fmeta and fmeta.fieldtype in ["Data", "Text", "Small Text", "Long Text",
+ "Link", "Select", "Read Only", "Text Editor"]):
+ or_filters.append([doctype, f.strip(), "like", "%{0}%".format(txt)])
if meta.get("fields", {"fieldname":"enabled", "fieldtype":"Check"}):
filters.append([doctype, "enabled", "=", 1])
@@ -76,13 +81,13 @@ def search_widget(doctype, txt, query=None, searchfield=None, start=0,
# find relevance as location of search term from the beginning of string `name`. used for sorting results.
fields.append("""locate("{_txt}", `tab{doctype}`.`name`) as `_relevance`""".format(
- _txt=frappe.db.escape((txt or "").replace("%", "")), doctype=doctype))
+ _txt=frappe.db.escape((txt or "").replace("%", "")), doctype=frappe.db.escape(doctype)))
values = frappe.desk.reportview.execute(doctype,
filters=filters, fields=fields,
or_filters = or_filters, limit_start = start,
limit_page_length=page_len,
- order_by="if(_relevance, _relevance, 99999), name asc".format(doctype),
+ order_by="if(_relevance, _relevance, 99999), modified desc".format(doctype),
ignore_permissions = True if doctype == "DocType" else False, # for dynamic links
as_list=True)
diff --git a/frappe/desk/tags.py b/frappe/desk/tags.py
index 174277314b..ea94eef7c5 100644
--- a/frappe/desk/tags.py
+++ b/frappe/desk/tags.py
@@ -62,7 +62,7 @@ def get_tags(doctype, txt):
for _user_tags in frappe.db.sql_list("""select `_user_tags`
from `tab{0}`
where _user_tags like '%{1}%'
- limit 1""".format(doctype, frappe.db.escape(txt))):
+ limit 1""".format(frappe.db.escape(doctype), frappe.db.escape(txt))):
tags.extend(_user_tags.split(","))
except Exception, e:
if e.args[0]!=1054: raise
diff --git a/frappe/docs/assets/img/add_user_roles.png b/frappe/docs/assets/img/add_user_roles.png
new file mode 100644
index 0000000000..49006acef9
Binary files /dev/null and b/frappe/docs/assets/img/add_user_roles.png differ
diff --git a/frappe/docs/assets/img/attach_image.gif b/frappe/docs/assets/img/attach_image.gif
new file mode 100644
index 0000000000..c360c8513e
Binary files /dev/null and b/frappe/docs/assets/img/attach_image.gif differ
diff --git a/frappe/docs/assets/img/autoname_and_search_field.png b/frappe/docs/assets/img/autoname_and_search_field.png
new file mode 100644
index 0000000000..ea801805e5
Binary files /dev/null and b/frappe/docs/assets/img/autoname_and_search_field.png differ
diff --git a/frappe/docs/assets/img/desk.png b/frappe/docs/assets/img/desk.png
new file mode 100644
index 0000000000..311ff5a7cb
Binary files /dev/null and b/frappe/docs/assets/img/desk.png differ
diff --git a/frappe/docs/assets/img/doctype_adding_field.png b/frappe/docs/assets/img/doctype_adding_field.png
new file mode 100644
index 0000000000..8ce7fdf284
Binary files /dev/null and b/frappe/docs/assets/img/doctype_adding_field.png differ
diff --git a/frappe/docs/assets/img/doctype_adding_permission.png b/frappe/docs/assets/img/doctype_adding_permission.png
new file mode 100644
index 0000000000..6853f42b01
Binary files /dev/null and b/frappe/docs/assets/img/doctype_adding_permission.png differ
diff --git a/frappe/docs/assets/img/doctype_article.png b/frappe/docs/assets/img/doctype_article.png
new file mode 100644
index 0000000000..3532ee2f74
Binary files /dev/null and b/frappe/docs/assets/img/doctype_article.png differ
diff --git a/frappe/docs/assets/img/doctype_lib_member.png b/frappe/docs/assets/img/doctype_lib_member.png
new file mode 100644
index 0000000000..3257fcf08e
Binary files /dev/null and b/frappe/docs/assets/img/doctype_lib_member.png differ
diff --git a/frappe/docs/assets/img/doctype_lib_membership.png b/frappe/docs/assets/img/doctype_lib_membership.png
new file mode 100644
index 0000000000..c32e348e1d
Binary files /dev/null and b/frappe/docs/assets/img/doctype_lib_membership.png differ
diff --git a/frappe/docs/assets/img/doctype_lib_trans.png b/frappe/docs/assets/img/doctype_lib_trans.png
new file mode 100644
index 0000000000..e7059290e9
Binary files /dev/null and b/frappe/docs/assets/img/doctype_lib_trans.png differ
diff --git a/frappe/docs/assets/img/doctype_new.png b/frappe/docs/assets/img/doctype_new.png
new file mode 100644
index 0000000000..e24c605e2b
Binary files /dev/null and b/frappe/docs/assets/img/doctype_new.png differ
diff --git a/frappe/docs/assets/img/fetch.png b/frappe/docs/assets/img/fetch.png
new file mode 100644
index 0000000000..3ac38b8e08
Binary files /dev/null and b/frappe/docs/assets/img/fetch.png differ
diff --git a/frappe/docs/assets/img/home.png b/frappe/docs/assets/img/home.png
new file mode 100644
index 0000000000..85e8e054b5
Binary files /dev/null and b/frappe/docs/assets/img/home.png differ
diff --git a/frappe/docs/assets/img/lib_management_module.png b/frappe/docs/assets/img/lib_management_module.png
new file mode 100644
index 0000000000..be2a5d9820
Binary files /dev/null and b/frappe/docs/assets/img/lib_management_module.png differ
diff --git a/frappe/docs/assets/img/lib_trans.png b/frappe/docs/assets/img/lib_trans.png
new file mode 100644
index 0000000000..6ab4dbfa48
Binary files /dev/null and b/frappe/docs/assets/img/lib_trans.png differ
diff --git a/frappe/docs/assets/img/link_field.png b/frappe/docs/assets/img/link_field.png
new file mode 100644
index 0000000000..dac6600809
Binary files /dev/null and b/frappe/docs/assets/img/link_field.png differ
diff --git a/frappe/docs/assets/img/login.png b/frappe/docs/assets/img/login.png
new file mode 100644
index 0000000000..217d03f612
Binary files /dev/null and b/frappe/docs/assets/img/login.png differ
diff --git a/frappe/docs/assets/img/naming_doctype.png b/frappe/docs/assets/img/naming_doctype.png
new file mode 100644
index 0000000000..ca109e7c5d
Binary files /dev/null and b/frappe/docs/assets/img/naming_doctype.png differ
diff --git a/frappe/docs/assets/img/new_article.png b/frappe/docs/assets/img/new_article.png
new file mode 100644
index 0000000000..6e17d82bfc
Binary files /dev/null and b/frappe/docs/assets/img/new_article.png differ
diff --git a/frappe/docs/assets/img/new_article_blank.png b/frappe/docs/assets/img/new_article_blank.png
new file mode 100644
index 0000000000..54c8d9152a
Binary files /dev/null and b/frappe/docs/assets/img/new_article_blank.png differ
diff --git a/frappe/docs/assets/img/new_lib_membership.png b/frappe/docs/assets/img/new_lib_membership.png
new file mode 100644
index 0000000000..ea8e16aa8b
Binary files /dev/null and b/frappe/docs/assets/img/new_lib_membership.png differ
diff --git a/frappe/docs/assets/img/new_member.png b/frappe/docs/assets/img/new_member.png
new file mode 100644
index 0000000000..0bf0cea89d
Binary files /dev/null and b/frappe/docs/assets/img/new_member.png differ
diff --git a/frappe/docs/assets/img/report.png b/frappe/docs/assets/img/report.png
new file mode 100644
index 0000000000..f0fe15bcfc
Binary files /dev/null and b/frappe/docs/assets/img/report.png differ
diff --git a/frappe/docs/assets/img/roles_creation.png b/frappe/docs/assets/img/roles_creation.png
new file mode 100644
index 0000000000..e2733d7cd6
Binary files /dev/null and b/frappe/docs/assets/img/roles_creation.png differ
diff --git a/frappe/docs/assets/img/select_field.png b/frappe/docs/assets/img/select_field.png
new file mode 100644
index 0000000000..4ac4f213ad
Binary files /dev/null and b/frappe/docs/assets/img/select_field.png differ
diff --git a/frappe/docs/assets/img/system_settings.png b/frappe/docs/assets/img/system_settings.png
new file mode 100644
index 0000000000..934dad3619
Binary files /dev/null and b/frappe/docs/assets/img/system_settings.png differ
diff --git a/frappe/docs/assets/img/tab_single.png b/frappe/docs/assets/img/tab_single.png
new file mode 100644
index 0000000000..e341313711
Binary files /dev/null and b/frappe/docs/assets/img/tab_single.png differ
diff --git a/frappe/docs/contents.html b/frappe/docs/contents.html
new file mode 100644
index 0000000000..59d0b4459d
--- /dev/null
+++ b/frappe/docs/contents.html
@@ -0,0 +1,10 @@
+
+
+
Table of Contents
+
+
+{% include "templates/includes/full_index.html" %}
+
+
+
+
diff --git a/frappe/docs/contents.py b/frappe/docs/contents.py
new file mode 100644
index 0000000000..131d4102a3
--- /dev/null
+++ b/frappe/docs/contents.py
@@ -0,0 +1,9 @@
+# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe.website.utils import get_full_index
+
+def get_context(context):
+ context.full_index = get_full_index(extn = True)
diff --git a/frappe/docs/current/api/config/frappe.config.core.html b/frappe/docs/current/api/config/frappe.config.core.html
new file mode 100644
index 0000000000..076ab88375
--- /dev/null
+++ b/frappe/docs/current/api/config/frappe.config.core.html
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.config.core.get_data
+ ()
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/config/frappe.config.desk.html b/frappe/docs/current/api/config/frappe.config.desk.html
new file mode 100644
index 0000000000..9cbb6f3e57
--- /dev/null
+++ b/frappe/docs/current/api/config/frappe.config.desk.html
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.config.desk.get_data
+ ()
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/config/frappe.config.desktop.html b/frappe/docs/current/api/config/frappe.config.desktop.html
new file mode 100644
index 0000000000..364501f7f4
--- /dev/null
+++ b/frappe/docs/current/api/config/frappe.config.desktop.html
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.config.desktop.get_data
+ ()
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/config/frappe.config.docs.html b/frappe/docs/current/api/config/frappe.config.docs.html
new file mode 100644
index 0000000000..3d994edfbf
--- /dev/null
+++ b/frappe/docs/current/api/config/frappe.config.docs.html
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.config.docs.get_context
+ (context)
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/config/frappe.config.html b/frappe/docs/current/api/config/frappe.config.html
new file mode 100644
index 0000000000..3a07c741a2
--- /dev/null
+++ b/frappe/docs/current/api/config/frappe.config.html
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/config/frappe.config.setup.html b/frappe/docs/current/api/config/frappe.config.setup.html
new file mode 100644
index 0000000000..cc86a04b13
--- /dev/null
+++ b/frappe/docs/current/api/config/frappe.config.setup.html
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.config.setup.get_data
+ ()
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/config/frappe.config.website.html b/frappe/docs/current/api/config/frappe.config.website.html
new file mode 100644
index 0000000000..a21900075c
--- /dev/null
+++ b/frappe/docs/current/api/config/frappe.config.website.html
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.config.website.get_data
+ ()
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/config/index.html b/frappe/docs/current/api/config/index.html
new file mode 100644
index 0000000000..41bede51b9
--- /dev/null
+++ b/frappe/docs/current/api/config/index.html
@@ -0,0 +1,19 @@
+
+
+
+
+
+
Package Contents
+
+{index}
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/config/index.txt b/frappe/docs/current/api/config/index.txt
new file mode 100644
index 0000000000..bedd42f359
--- /dev/null
+++ b/frappe/docs/current/api/config/index.txt
@@ -0,0 +1,7 @@
+frappe.config.core
+frappe.config.desk
+frappe.config.desktop
+frappe.config.docs
+frappe.config
+frappe.config.setup
+frappe.config.website
\ No newline at end of file
diff --git a/frappe/docs/current/api/core/frappe.core.html b/frappe/docs/current/api/core/frappe.core.html
new file mode 100644
index 0000000000..75283a7e66
--- /dev/null
+++ b/frappe/docs/current/api/core/frappe.core.html
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/core/frappe.core.notifications.html b/frappe/docs/current/api/core/frappe.core.notifications.html
new file mode 100644
index 0000000000..c2e7eb0794
--- /dev/null
+++ b/frappe/docs/current/api/core/frappe.core.notifications.html
@@ -0,0 +1,82 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.core.notifications.get_notification_config
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.core.notifications.get_things_todo
+ ()
+
+
Returns a count of incomplete todos
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.core.notifications.get_todays_events
+ ()
+
+
Returns a count of todays events in calendar
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.core.notifications.get_unread_messages
+ ()
+
+
returns unread (docstatus-0 messages for a user)
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/core/index.html b/frappe/docs/current/api/core/index.html
new file mode 100644
index 0000000000..6f60981f39
--- /dev/null
+++ b/frappe/docs/current/api/core/index.html
@@ -0,0 +1,19 @@
+
+
+
+
+
+
Package Contents
+
+{index}
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/core/index.txt b/frappe/docs/current/api/core/index.txt
new file mode 100644
index 0000000000..7bf21e3723
--- /dev/null
+++ b/frappe/docs/current/api/core/index.txt
@@ -0,0 +1,2 @@
+frappe.core
+frappe.core.notifications
\ No newline at end of file
diff --git a/frappe/docs/current/api/custom/frappe.custom.html b/frappe/docs/current/api/custom/frappe.custom.html
new file mode 100644
index 0000000000..e40cbe0098
--- /dev/null
+++ b/frappe/docs/current/api/custom/frappe.custom.html
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/custom/index.html b/frappe/docs/current/api/custom/index.html
new file mode 100644
index 0000000000..4d659752b2
--- /dev/null
+++ b/frappe/docs/current/api/custom/index.html
@@ -0,0 +1,19 @@
+
+
+
+
+
+
Package Contents
+
+{index}
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/custom/index.txt b/frappe/docs/current/api/custom/index.txt
new file mode 100644
index 0000000000..adeae6e90d
--- /dev/null
+++ b/frappe/docs/current/api/custom/index.txt
@@ -0,0 +1 @@
+frappe.custom
\ No newline at end of file
diff --git a/frappe/docs/current/api/desk/form/frappe.desk.form.assign_to.html b/frappe/docs/current/api/desk/form/frappe.desk.form.assign_to.html
new file mode 100644
index 0000000000..6821c8018b
--- /dev/null
+++ b/frappe/docs/current/api/desk/form/frappe.desk.form.assign_to.html
@@ -0,0 +1,157 @@
+
+
+
+
+
+
+
+
+
Class DuplicateToDoError
+
+
Inherits from frappe.exceptions.ValidationError
+
+
+
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.desk.form.assign_to.add
+
+
+
+
+ frappe.desk.form.assign_to.add
+ (args=None)
+
+
add in someone's to do list
+args = {
+ "assign_to": ,
+ "doctype": ,
+ "name": ,
+ "description":
+}
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.desk.form.assign_to.add_multiple
+
+
+
+
+ frappe.desk.form.assign_to.add_multiple
+ (args=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.form.assign_to.clear
+ (doctype, name)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.form.assign_to.get
+ (args=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.form.assign_to.notify_assignment
+ (assigned_by, owner, doc_type, doc_name, action=CLOSE, description=None, notify=0)
+
+
Notify assignee that there is a change in assignment
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.desk.form.assign_to.remove
+
+
+
+
+ frappe.desk.form.assign_to.remove
+ (doctype, name, assign_to)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.form.assign_to.remove_from_todo_if_already_assigned
+ (doctype, docname)
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/desk/form/frappe.desk.form.html b/frappe/docs/current/api/desk/form/frappe.desk.form.html
new file mode 100644
index 0000000000..6324e42c50
--- /dev/null
+++ b/frappe/docs/current/api/desk/form/frappe.desk.form.html
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/desk/form/frappe.desk.form.linked_with.html b/frappe/docs/current/api/desk/form/frappe.desk.form.linked_with.html
new file mode 100644
index 0000000000..c4beb0c7bf
--- /dev/null
+++ b/frappe/docs/current/api/desk/form/frappe.desk.form.linked_with.html
@@ -0,0 +1,107 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.form.linked_with._get_linked_doctypes
+ (doctype)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.form.linked_with.get_dynamic_linked_fields
+ (doctype)
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.desk.form.linked_with.get_linked_docs
+
+
+
+
+ frappe.desk.form.linked_with.get_linked_docs
+ (doctype, name, linkinfo=None)
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.desk.form.linked_with.get_linked_doctypes
+
+
+
+
+ frappe.desk.form.linked_with.get_linked_doctypes
+ (doctype)
+
+
add list of doctypes this doctype is 'linked' with.
+
+
Example, for Customer:
+
+
{"Address": {"fieldname": "customer"}..}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.form.linked_with.get_linked_fields
+ (doctype)
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/desk/form/frappe.desk.form.load.html b/frappe/docs/current/api/desk/form/frappe.desk.form.load.html
new file mode 100644
index 0000000000..2a324d6acb
--- /dev/null
+++ b/frappe/docs/current/api/desk/form/frappe.desk.form.load.html
@@ -0,0 +1,188 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.form.load.get_assignments
+ (dt, dn)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.form.load.get_attachments
+ (dt, dn)
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.desk.form.load.get_badge_info
+
+
+
+
+ frappe.desk.form.load.get_badge_info
+ (doctypes, filters)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.form.load.get_comments
+ (dt, dn, limit=100)
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.desk.form.load.get_docinfo
+
+
+
+
+ frappe.desk.form.load.get_docinfo
+ (doc=None, doctype=None, name=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.form.load.get_meta_bundle
+ (doctype)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.form.load.get_user_permissions
+ (meta)
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.desk.form.load.getdoc
+
+
+
+
+ frappe.desk.form.load.getdoc
+ (doctype, name, user=None)
+
+
Loads a doclist for a given document. This method is called directly from the client.
+Requries "doctype", "name" as form variables.
+Will also call the "onload" method on the document.
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.desk.form.load.getdoctype
+
+
+
+
+ frappe.desk.form.load.getdoctype
+ (doctype, with_parent=False, cached_timestamp=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.form.load.run_onload
+ (doc)
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/desk/form/frappe.desk.form.meta.html b/frappe/docs/current/api/desk/form/frappe.desk.form.meta.html
new file mode 100644
index 0000000000..028cb9249a
--- /dev/null
+++ b/frappe/docs/current/api/desk/form/frappe.desk.form.meta.html
@@ -0,0 +1,277 @@
+
+
+
+
+
+
+
+
+
Class FormMeta
+
+
Inherits from frappe.model.meta.Meta
+
+
+
+
+
+
+
+
+
+
+ __init__
+ (self, doctype)
+
+
+
+
+
+
+
+
+
+
+
+ _add_code
+ (self, path, fieldname)
+
+
+
+
+
+
+
+
+
+
+
+ add_code
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ add_code_via_hook
+ (self, hook, fieldname)
+
+
+
+
+
+
+
+
+
+
+
+ add_custom_script
+ (self)
+
+
embed all require files
+
+
+
+
+
+
+
+
+
+
+ add_html_templates
+ (self, path)
+
+
+
+
+
+
+
+
+
+
+
+ add_linked_document_type
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ add_search_fields
+ (self)
+
+
add search fields found in the doctypes indicated by link fields' options
+
+
+
+
+
+
+
+
+
+
+ as_dict
+ (self, no_nulls=False)
+
+
+
+
+
+
+
+
+
+
+
+ load_assets
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ load_print_formats
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ load_templates
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ load_workflows
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ set_translations
+ (self, lang)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.form.meta.get_code_files_via_hooks
+ (hook, name)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.form.meta.get_js
+ (path)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.form.meta.get_meta
+ (doctype, cached=True)
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/desk/form/frappe.desk.form.run_method.html b/frappe/docs/current/api/desk/form/frappe.desk.form.run_method.html
new file mode 100644
index 0000000000..e42c55176b
--- /dev/null
+++ b/frappe/docs/current/api/desk/form/frappe.desk.form.run_method.html
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.form.run_method.make_csv_output
+ (res, dt)
+
+
send method response as downloadable CSV file
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.desk.form.run_method.runserverobj
+
+
+
+
+ frappe.desk.form.run_method.runserverobj
+ (method, docs=None, dt=None, dn=None, arg=None, args=None)
+
+
run controller method - old style
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/desk/form/frappe.desk.form.save.html b/frappe/docs/current/api/desk/form/frappe.desk.form.save.html
new file mode 100644
index 0000000000..419a6dbf7d
--- /dev/null
+++ b/frappe/docs/current/api/desk/form/frappe.desk.form.save.html
@@ -0,0 +1,86 @@
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.desk.form.save.cancel
+
+
+
+
+ frappe.desk.form.save.cancel
+ (doctype=None, name=None, workflow_state_fieldname=None, workflow_state=None)
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.desk.form.save.savedocs
+
+
+
+
+ frappe.desk.form.save.savedocs
+ ()
+
+
save / submit / update doclist
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.form.save.send_updated_docs
+ (doc)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.form.save.set_local_name
+ (doc)
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/desk/form/frappe.desk.form.test_form.html b/frappe/docs/current/api/desk/form/frappe.desk.form.test_form.html
new file mode 100644
index 0000000000..6b2a1689e7
--- /dev/null
+++ b/frappe/docs/current/api/desk/form/frappe.desk.form.test_form.html
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+
+
Class TestForm
+
+
Inherits from unittest.case.TestCase
+
+
+
+
+
+
+
+
+
+
+ test_linked_with
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/desk/form/frappe.desk.form.utils.html b/frappe/docs/current/api/desk/form/frappe.desk.form.utils.html
new file mode 100644
index 0000000000..563ac23b76
--- /dev/null
+++ b/frappe/docs/current/api/desk/form/frappe.desk.form.utils.html
@@ -0,0 +1,90 @@
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.desk.form.utils.add_comment
+
+
+
+
+ frappe.desk.form.utils.add_comment
+ (doc)
+
+
allow any logged user to post a comment
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.desk.form.utils.get_next
+
+
+
+
+ frappe.desk.form.utils.get_next
+ (doctype, value, prev, filters=None, order_by=modified desc)
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.desk.form.utils.remove_attach
+
+
+
+
+ frappe.desk.form.utils.remove_attach
+ ()
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.desk.form.utils.validate_link
+
+
+
+
+ frappe.desk.form.utils.validate_link
+ ()
+
+
validate link when updated by user
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/desk/form/index.html b/frappe/docs/current/api/desk/form/index.html
new file mode 100644
index 0000000000..10817cf436
--- /dev/null
+++ b/frappe/docs/current/api/desk/form/index.html
@@ -0,0 +1,19 @@
+
+
+
+
+
+
Package Contents
+
+{index}
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/desk/form/index.txt b/frappe/docs/current/api/desk/form/index.txt
new file mode 100644
index 0000000000..1bcd9b9b51
--- /dev/null
+++ b/frappe/docs/current/api/desk/form/index.txt
@@ -0,0 +1,9 @@
+frappe.desk.form.assign_to
+frappe.desk.form
+frappe.desk.form.linked_with
+frappe.desk.form.load
+frappe.desk.form.meta
+frappe.desk.form.run_method
+frappe.desk.form.save
+frappe.desk.form.test_form
+frappe.desk.form.utils
\ No newline at end of file
diff --git a/frappe/docs/current/api/desk/frappe.desk.calendar.html b/frappe/docs/current/api/desk/frappe.desk.calendar.html
new file mode 100644
index 0000000000..66cf7de769
--- /dev/null
+++ b/frappe/docs/current/api/desk/frappe.desk.calendar.html
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.calendar.get_event_conditions
+ (doctype, filters=None)
+
+
Returns SQL conditions with user permissions and filters for event queries
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.desk.calendar.update_event
+
+
+
+
+ frappe.desk.calendar.update_event
+ (args, field_map)
+
+
Updates Event (called via calendar) based on passed field_map
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/desk/frappe.desk.desk_page.html b/frappe/docs/current/api/desk/frappe.desk.desk_page.html
new file mode 100644
index 0000000000..634e08abeb
--- /dev/null
+++ b/frappe/docs/current/api/desk/frappe.desk.desk_page.html
@@ -0,0 +1,70 @@
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.desk.desk_page.get
+
+
+
+
+ frappe.desk.desk_page.get
+ (name)
+
+
Return the :term:doclist of the Page specified by name
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.desk.desk_page.getpage
+
+
+
+
+ frappe.desk.desk_page.getpage
+ ()
+
+
Load the page from frappe.form and send it via frappe.response
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.desk_page.has_permission
+ (page)
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/desk/frappe.desk.html b/frappe/docs/current/api/desk/frappe.desk.html
new file mode 100644
index 0000000000..babfe9339b
--- /dev/null
+++ b/frappe/docs/current/api/desk/frappe.desk.html
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/desk/frappe.desk.moduleview.html b/frappe/docs/current/api/desk/frappe.desk.moduleview.html
new file mode 100644
index 0000000000..06f057431b
--- /dev/null
+++ b/frappe/docs/current/api/desk/frappe.desk.moduleview.html
@@ -0,0 +1,261 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.moduleview.add_custom_doctypes
+ (data, doctype_info)
+
+
Adds Custom DocTypes to modules setup via config/desktop.py.
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.moduleview.add_section
+ (data, label, icon, items)
+
+
Adds a section to the module data.
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.moduleview.add_setup_section
+ (config, app, module, label, icon)
+
+
Add common sections to /desk#Module/Setup
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.moduleview.apply_permissions
+ (data)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.moduleview.build_config_from_file
+ (module)
+
+
Build module info from app/config/desktop.py files.
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.moduleview.build_standard_config
+ (module, doctype_info)
+
+
Build standard module data from DocTypes.
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.moduleview.combine_common_sections
+ (data)
+
+
Combine sections declared in separate apps.
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.desk.moduleview.get
+
+
+
+
+ frappe.desk.moduleview.get
+ (module)
+
+
Returns data (sections, list of reports, counts) to render module view in desk:
+/desk/#Module/[name].
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.moduleview.get_config
+ (app, module)
+
+
Load module info from [app].config.[module].
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.moduleview.get_data
+ (module)
+
+
Get module data for the module view desk/#Module/[name]
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.moduleview.get_doctype_info
+ (module)
+
+
Returns list of non child DocTypes for given module.
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.moduleview.get_last_modified
+ (doctype)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.moduleview.get_report_list
+ (module, is_standard=No)
+
+
Returns list on new style reports for modules.
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.moduleview.get_setup_section
+ (app, module, label, icon)
+
+
Get the setup section from each module (for global Setup page).
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.moduleview.set_last_modified
+ (data)
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/desk/frappe.desk.notifications.html b/frappe/docs/current/api/desk/frappe.desk.notifications.html
new file mode 100644
index 0000000000..799d78174c
--- /dev/null
+++ b/frappe/docs/current/api/desk/frappe.desk.notifications.html
@@ -0,0 +1,164 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.notifications.clear_doctype_notifications
+ (doc, method=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.notifications.clear_notifications
+ (user=*)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.notifications.delete_notification_count_for
+ (doctype)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.notifications.get_new_messages
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.notifications.get_notification_config
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.notifications.get_notification_info_for_boot
+ ()
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.desk.notifications.get_notifications
+
+
+
+
+ frappe.desk.notifications.get_notifications
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.notifications.get_notifications_for_doctypes
+ (config, notification_count)
+
+
Notifications for DocTypes
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.notifications.get_notifications_for_modules
+ (config, notification_count)
+
+
Notifications for modules
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/desk/frappe.desk.query_builder.html b/frappe/docs/current/api/desk/frappe.desk.query_builder.html
new file mode 100644
index 0000000000..922de50440
--- /dev/null
+++ b/frappe/docs/current/api/desk/frappe.desk.query_builder.html
@@ -0,0 +1,183 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.query_builder.add_limit_to_query
+ (query, args)
+
+
Add limit condition to query
+can be used by methods called in listing to add limit condition
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.query_builder.add_match_conditions
+ (q, tl)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.query_builder.build_description_simple
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.query_builder.build_description_standard
+ (meta, tl)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.query_builder.get_parent_dt
+ (dt)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.query_builder.get_sql_meta
+ (tl)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.query_builder.get_sql_tables
+ (q)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.query_builder.guess_type
+ (m)
+
+
Returns fieldtype depending on the MySQLdb Description
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.desk.query_builder.runquery
+
+
+
+
+ frappe.desk.query_builder.runquery
+ (q=, ret=0, from_export=0)
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.desk.query_builder.runquery_csv
+
+
+
+
+ frappe.desk.query_builder.runquery_csv
+ ()
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/desk/frappe.desk.query_report.html b/frappe/docs/current/api/desk/frappe.desk.query_report.html
new file mode 100644
index 0000000000..2646288191
--- /dev/null
+++ b/frappe/docs/current/api/desk/frappe.desk.query_report.html
@@ -0,0 +1,193 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.query_report.add_total_row
+ (result, columns)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.query_report.get_columns_dict
+ (columns)
+
+
Returns a dict with column docfield values as dict
+The keys for the dict are both idx and fieldname,
+so either index or fieldname can be used to search for a column's docfield properties
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.query_report.get_filtered_data
+ (ref_doctype, columns, data)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.query_report.get_linked_doctypes
+ (columns, data)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.query_report.get_report_doc
+ (report_name)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.query_report.get_report_module_dotted_path
+ (module, report_name)
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.desk.query_report.get_script
+
+
+
+
+ frappe.desk.query_report.get_script
+ (report_name)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.query_report.get_user_match_filters
+ (doctypes, ref_doctype)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.query_report.has_match
+ (row, linked_doctypes, doctype_match_filters, ref_doctype, if_owner, columns_dict)
+
+
Returns True if after evaluating permissions for each linked doctype
+- There is an owner match for the ref_doctype
+- and There is a user permission match for all linked doctypes
+
+
Returns True if the row is empty
+
+
Note:
+Each doctype could have multiple conflicting user permission doctypes.
+Hence even if one of the sets allows a match, it is true.
+This behavior is equivalent to the trickling of user permissions of linked doctypes to the ref doctype.
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.desk.query_report.run
+
+
+
+
+ frappe.desk.query_report.run
+ (report_name, filters=())
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/desk/frappe.desk.report_dump.html b/frappe/docs/current/api/desk/frappe.desk.report_dump.html
new file mode 100644
index 0000000000..f57cd7ca87
--- /dev/null
+++ b/frappe/docs/current/api/desk/frappe.desk.report_dump.html
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.desk.report_dump.get_data
+
+
+
+
+ frappe.desk.report_dump.get_data
+ (doctypes, last_modified)
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/desk/frappe.desk.reportview.html b/frappe/docs/current/api/desk/frappe.desk.reportview.html
new file mode 100644
index 0000000000..2fab012752
--- /dev/null
+++ b/frappe/docs/current/api/desk/frappe.desk.reportview.html
@@ -0,0 +1,220 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.reportview.build_match_conditions
+ (doctype, as_condition=True)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.reportview.compress
+ (data)
+
+
separate keys and values
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.desk.reportview.delete_items
+
+
+
+
+ frappe.desk.reportview.delete_items
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.reportview.execute
+ (doctype)
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.desk.reportview.export_query
+
+
+
+
+ frappe.desk.reportview.export_query
+ ()
+
+
export from report builder
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.desk.reportview.get
+
+
+
+
+ frappe.desk.reportview.get
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.reportview.get_form_params
+ ()
+
+
Stringify GET request parameters.
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.reportview.get_labels
+ (fields, doctype)
+
+
get column labels based on column names
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.reportview.get_match_cond
+ (doctype)
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.desk.reportview.get_stats
+
+
+
+
+ frappe.desk.reportview.get_stats
+ (stats, doctype)
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.desk.reportview.save_report
+
+
+
+
+ frappe.desk.reportview.save_report
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.reportview.scrub_user_tags
+ (tagcount)
+
+
rebuild tag list for tags
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/desk/frappe.desk.search.html b/frappe/docs/current/api/desk/frappe.desk.search.html
new file mode 100644
index 0000000000..2ae8c3e30b
--- /dev/null
+++ b/frappe/docs/current/api/desk/frappe.desk.search.html
@@ -0,0 +1,102 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.search.build_for_autosuggest
+ (res)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.search.get_std_fields_list
+ (meta, key)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.search.scrub_custom_query
+ (query, key, txt)
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.desk.search.search_link
+
+
+
+
+ frappe.desk.search.search_link
+ (doctype, txt, query=None, filters=None, page_len=20, searchfield=None)
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.desk.search.search_widget
+
+
+
+
+ frappe.desk.search.search_widget
+ (doctype, txt, query=None, searchfield=None, start=0, page_len=50, filters=None)
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/desk/frappe.desk.star.html b/frappe/docs/current/api/desk/frappe.desk.star.html
new file mode 100644
index 0000000000..94ce433135
--- /dev/null
+++ b/frappe/docs/current/api/desk/frappe.desk.star.html
@@ -0,0 +1,64 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.star._toggle_star
+ (doctype, name, add=False, user=None)
+
+
Same as toggle_star but hides param user from API
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.desk.star.toggle_star
+
+
+
+
+ frappe.desk.star.toggle_star
+ (doctype, name, add=False)
+
+
Adds / removes the current user in the __starred_by property of the given document.
+If column does not exist, will add it in the database.
+
+
The _starred_by property is always set from this function and is ignored if set via
+Document API
+
+
Parameters:
+
+
+doctype - DocType of the document to star
+name - Name of the document to star
+add - Yes if star is to be added. If not Yes the star will be removed.
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/desk/frappe.desk.tags.html b/frappe/docs/current/api/desk/frappe.desk.tags.html
new file mode 100644
index 0000000000..70efde766b
--- /dev/null
+++ b/frappe/docs/current/api/desk/frappe.desk.tags.html
@@ -0,0 +1,213 @@
+
+
+
+
+
+
+
+
+
Class DocTags
+
+
Tags for a particular doctype
+
+
+
+
+
+
+
+
+
+ __init__
+ (self, dt)
+
+
+
+
+
+
+
+
+
+
+
+ add
+ (self, dn, tag)
+
+
+
+
+
+
+
+
+
+
+
+ get_tag_fields
+ (self)
+
+
returns tag_fields property
+
+
+
+
+
+
+
+
+
+
+ get_tags
+ (self, dn)
+
+
returns tag for a particular item
+
+
+
+
+
+
+
+
+
+
+ remove
+ (self, dn, tag)
+
+
+
+
+
+
+
+
+
+
+
+ remove_all
+ (self, dn)
+
+
remove all user tags (call before delete)
+
+
+
+
+
+
+
+
+
+
+ setup
+ (self)
+
+
adds the user tags column if not exists
+
+
+
+
+
+
+
+
+
+
+ update
+ (self, dn, tl)
+
+
updates the user tag column in the table
+
+
+
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.desk.tags.add_tag
+
+
+
+
+ frappe.desk.tags.add_tag
+ ()
+
+
adds a new tag to a record, and creates the Tag master
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.tags.check_user_tags
+ (dt)
+
+
if the user does not have a tags column, then it creates one
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.desk.tags.get_tags
+
+
+
+
+ frappe.desk.tags.get_tags
+ (doctype, txt)
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.desk.tags.remove_tag
+
+
+
+
+ frappe.desk.tags.remove_tag
+ ()
+
+
removes tag from the record
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/desk/index.html b/frappe/docs/current/api/desk/index.html
new file mode 100644
index 0000000000..1e332a5d66
--- /dev/null
+++ b/frappe/docs/current/api/desk/index.html
@@ -0,0 +1,19 @@
+
+
+
+
+
+
Package Contents
+
+{index}
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/desk/index.txt b/frappe/docs/current/api/desk/index.txt
new file mode 100644
index 0000000000..439207c279
--- /dev/null
+++ b/frappe/docs/current/api/desk/index.txt
@@ -0,0 +1,12 @@
+frappe.desk.calendar
+frappe.desk.desk_page
+frappe.desk
+frappe.desk.moduleview
+frappe.desk.notifications
+frappe.desk.query_builder
+frappe.desk.query_report
+frappe.desk.report_dump
+frappe.desk.reportview
+frappe.desk.search
+frappe.desk.star
+frappe.desk.tags
\ No newline at end of file
diff --git a/frappe/docs/current/api/email/frappe.email.bulk.html b/frappe/docs/current/api/email/frappe.email.bulk.html
new file mode 100644
index 0000000000..d45563832b
--- /dev/null
+++ b/frappe/docs/current/api/email/frappe.email.bulk.html
@@ -0,0 +1,197 @@
+
+
+
+
+
+
+
+
+
Class BulkLimitCrossedError
+
+
Inherits from frappe.exceptions.ValidationError
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.email.bulk.add
+ (email, sender, subject, formatted, text_content=None, reference_doctype=None, reference_name=None, attachments=None, reply_to=None, cc=(), message_id=None, send_after=None, bulk_priority=1)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.email.bulk.check_bulk_limit
+ (recipients)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.email.bulk.clear_outbox
+ ()
+
+
Remove mails older than 31 days in Outbox. Called daily via scheduler.
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.email.bulk.flush
+ (from_test=False)
+
+
flush email queue, every time: called from scheduler
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.email.bulk.get_unsubcribed_url
+ (reference_doctype, reference_name, email, unsubscribe_method, unsubscribe_params)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.email.bulk.get_unsubscribe_link
+ (reference_doctype, reference_name, email, recipients, expose_recipients, show_as_cc, unsubscribe_method, unsubscribe_params, unsubscribe_message)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.email.bulk.return_unsubscribed_page
+ (email, doctype, name)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.email.bulk.send
+ (recipients=None, sender=None, subject=None, message=None, reference_doctype=None, reference_name=None, unsubscribe_method=None, unsubscribe_params=None, unsubscribe_message=None, attachments=None, reply_to=None, cc=(), show_as_cc=(), message_id=None, send_after=None, expose_recipients=False, bulk_priority=1)
+
+
Add email to sending queue (Bulk Email)
+
+
Parameters:
+
+
+recipients - List of recipients.
+sender - Email sender.
+subject - Email subject.
+message - Email message.
+reference_doctype - Reference DocType of caller document.
+reference_name - Reference name of caller document.
+bulk_priority - Priority for bulk email, default 1.
+unsubscribe_method - URL method for unsubscribe. Default is /api/method/frappe.email.bulk.unsubscribe.
+unsubscribe_params - additional params for unsubscribed links. default are name, doctype, email
+attachments - Attachments to be sent.
+reply_to - Reply to be captured here (default inbox)
+message_id - Used for threading. If a reply is received to this email, Message-Id is sent back as In-Reply-To in received email.
+send_after - Send this email after the given datetime. If value is in integer, then send_after will be the automatically set to no of days from current date.
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.email.bulk.unsubscribe
+
+
+
+
+ frappe.email.bulk.unsubscribe
+ (doctype, name, email)
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/email/frappe.email.email_body.html b/frappe/docs/current/api/email/frappe.email.email_body.html
new file mode 100644
index 0000000000..5d0c374191
--- /dev/null
+++ b/frappe/docs/current/api/email/frappe.email.email_body.html
@@ -0,0 +1,293 @@
+
+
+
+
+
+
+
+
+
Class EMail
+
+
Wrapper on the email module. Email object represents emails to be sent to the client.
+Also provides a clean way to add binary FileData attachments
+Also sets all messages as multipart/alternative for cleaner reading in text-only clients
+
+
+
+
+
+
+
+
+
+ __init__
+ (self, sender=, recipients=(), subject=, alternative=0, reply_to=None, cc=())
+
+
+
+
+
+
+
+
+
+
+
+ add_attachment
+ (self, fname, fcontent, content_type=None)
+
+
+
+
+
+
+
+
+
+
+
+ add_pdf_attachment
+ (self, name, html, options=None)
+
+
+
+
+
+
+
+
+
+
+
+ as_string
+ (self)
+
+
validate, build message and convert to string
+
+
+
+
+
+
+
+
+
+
+ attach_file
+ (self, n)
+
+
attach a file from the FileData table
+
+
+
+
+
+
+
+
+
+
+ get_default_sender
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ make
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ set_html
+ (self, message, text_content=None, footer=None, print_html=None, formatted=None)
+
+
Attach message in the html portion of multipart/alternative
+
+
+
+
+
+
+
+
+
+
+ set_html_as_text
+ (self, html)
+
+
+
+
+
+
+
+
+
+
+
+ set_message
+ (self, message, mime_type=text/html, as_attachment=0, filename=attachment.html)
+
+
Append the message with MIME content to the root node (as attachment)
+
+
+
+
+
+
+
+
+
+
+ set_message_id
+ (self, message_id)
+
+
+
+
+
+
+
+
+
+
+
+ set_part_html
+ (self, message)
+
+
+
+
+
+
+
+
+
+
+
+ set_text
+ (self, message)
+
+
Attach message in the text portion of multipart/alternative
+
+
+
+
+
+
+
+
+
+
+ validate
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.email.email_body.get_email
+ (recipients, sender=, msg=, subject=[No Subject], text_content=None, footer=None, print_html=None, formatted=None, attachments=None, content=None, reply_to=None, cc=())
+
+
send an html email as multipart with attachments and all
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.email.email_body.get_footer
+ (email_account, footer=None)
+
+
append a footer (signature)
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.email.email_body.get_formatted_html
+ (subject, message, footer=None, print_html=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.email.email_body.get_signature
+ (email_account)
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/email/frappe.email.html b/frappe/docs/current/api/email/frappe.email.html
new file mode 100644
index 0000000000..df731820b5
--- /dev/null
+++ b/frappe/docs/current/api/email/frappe.email.html
@@ -0,0 +1,100 @@
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.email.get_contact_list
+
+
+
+
+ frappe.email.get_contact_list
+ ()
+
+
Returns contacts (from autosuggest)
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.email.get_system_managers
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.email.sendmail
+ (recipients, sender=, msg=, subject=[No Subject], attachments=None, content=None, reply_to=None, cc=(), message_id=None)
+
+
send an html email as multipart with attachments and all
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.email.sendmail_md
+ (recipients, sender=None, msg=None, subject=None, attachments=None, content=None, reply_to=None, cc=(), message_id=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.email.sendmail_to_system_managers
+ (subject, content)
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/email/frappe.email.receive.html b/frappe/docs/current/api/email/frappe.email.receive.html
new file mode 100644
index 0000000000..92efdd8ea8
--- /dev/null
+++ b/frappe/docs/current/api/email/frappe.email.receive.html
@@ -0,0 +1,731 @@
+
+
+
+
+
+
+
+
+
Class Email
+
+
+
+
+
+
+
+
+
+
+ __init__
+ (self, content)
+
+
Parses headers, content, attachments from given raw message.
+
+
Parameters:
+
+
+content - Raw message.
+
+
+
+
+
+
+
+
+
+
+
+ get_attachment
+ (self, part, charset)
+
+
+
+
+
+
+
+
+
+
+
+ get_charset
+ (self, part)
+
+
+
+
+
+
+
+
+
+
+
+ get_payload
+ (self, part, charset)
+
+
+
+
+
+
+
+
+
+
+
+ get_thread_id
+ (self)
+
+
Extract thread ID from []
+
+
+
+
+
+
+
+
+
+
+ parse
+ (self)
+
+
Walk and process multi-part email.
+
+
+
+
+
+
+
+
+
+
+ process_part
+ (self, part)
+
+
Parse email part and set it to text_content, html_content or attachments.
+
+
+
+
+
+
+
+
+
+
+ save_attachments_in_doc
+ (self, doc)
+
+
Save email attachments in given document.
+
+
+
+
+
+
+
+
+
+
+ set_content_and_type
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ set_subject
+ (self)
+
+
Parse and decode Subject header.
+
+
+
+
+
+
+
+
+
+
+
+
Class EmailServer
+
+
Wrapper for POP server to pull emails.
+
+
+
+
+
+
+
+
+
+ __init__
+ (self, args=None)
+
+
+
+
+
+
+
+
+
+
+
+ check_mails
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ connect
+ (self)
+
+
Connect to Email Account .
+
+
+
+
+
+
+
+
+
+
+ connect_imap
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ connect_pop
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ get_messages
+ (self)
+
+
Returns new email messages in a list.
+
+
+
+
+
+
+
+
+
+
+ get_new_mails
+ (self)
+
+
Return list of new mails
+
+
+
+
+
+
+
+
+
+
+ has_login_limit_exceeded
+ (self, e)
+
+
+
+
+
+
+
+
+
+
+
+ is_temporary_system_problem
+ (self, e)
+
+
+
+
+
+
+
+
+
+
+
+ make_error_msg
+ (self, msg_num, incoming_mail)
+
+
+
+
+
+
+
+
+
+
+
+ process_message
+ (self, mail)
+
+
+
+
+
+
+
+
+
+
+
+ retrieve_message
+ (self, message_meta, msg_num=None)
+
+
+
+
+
+
+
+
+
+
+
+ setup
+ (self, args=None)
+
+
+
+
+
+
+
+
+
+
+
+ validate_message_limits
+ (self, message_meta)
+
+
+
+
+
+
+
+
+
+
+
+
+
Class EmailSizeExceededError
+
+
Inherits from frappe.exceptions.ValidationError
+
+
+
+
+
+
+
+
+
+
+
+
Class EmailTimeoutError
+
+
Inherits from frappe.exceptions.ValidationError
+
+
+
+
+
+
+
+
+
+
+
+
Class LoginLimitExceeded
+
+
Inherits from frappe.exceptions.ValidationError
+
+
+
+
+
+
+
+
+
+
+
+
Class Timed_IMAP4
+
+
Inherits from frappe.email.receive.TimerMixin, imaplib.IMAP4
+
+
+
+
+
+
+
+
+
+
+ __init__
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ _getline
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ quit
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+
+
Class Timed_IMAP4_SSL
+
+
Inherits from frappe.email.receive.TimerMixin, imaplib.IMAP4_SSL
+
+
+
+
+
+
+
+
+
+
+ __init__
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ _getline
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ quit
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+
+
Class Timed_POP3
+
+
Inherits from frappe.email.receive.TimerMixin, poplib.POP3
+
+
+
+
+
+
+
+
+
+
+ __init__
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ _getline
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ quit
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+
+
Class Timed_POP3_SSL
+
+
Inherits from frappe.email.receive.TimerMixin, poplib.POP3_SSL
+
+
+
+
+
+
+
+
+
+
+ __init__
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ _getline
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ quit
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+
+
Class TimerMixin
+
+
Inherits from __builtin__.object
+
+
+
+
+
+
+
+
+
+
+ __init__
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ _getline
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ quit
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+
+
Class TotalSizeExceededError
+
+
Inherits from frappe.exceptions.ValidationError
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/email/frappe.email.smtp.html b/frappe/docs/current/api/email/frappe.email.smtp.html
new file mode 100644
index 0000000000..caa9af2cd1
--- /dev/null
+++ b/frappe/docs/current/api/email/frappe.email.smtp.html
@@ -0,0 +1,125 @@
+
+
+
+
+
+
+
+
+
Class SMTPServer
+
+
+
+
+
+
+
+
+
+
+ __init__
+ (self, login=None, password=None, server=None, port=None, use_ssl=None, append_to=None)
+
+
+
+
+
+
+
+
+
+
+
+ setup_email_account
+ (self, append_to=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.email.smtp._get_email_account
+ (filters)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.email.smtp.get_default_outgoing_email_account
+ (raise_exception_not_set=True)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.email.smtp.get_outgoing_email_account
+ (raise_exception_not_set=True, append_to=None)
+
+
Returns outgoing email account based on append_to or the default
+outgoing account. If default outgoing account is not found, it will
+try getting settings from site_config.json.
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.email.smtp.send
+ (email, append_to=None)
+
+
send the message or add it to Outbox Email
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/email/index.html b/frappe/docs/current/api/email/index.html
new file mode 100644
index 0000000000..66d5d339d3
--- /dev/null
+++ b/frappe/docs/current/api/email/index.html
@@ -0,0 +1,19 @@
+
+
+
+
+
+
Package Contents
+
+{index}
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/email/index.txt b/frappe/docs/current/api/email/index.txt
new file mode 100644
index 0000000000..cf44b156d7
--- /dev/null
+++ b/frappe/docs/current/api/email/index.txt
@@ -0,0 +1,5 @@
+frappe.email.bulk
+frappe.email.email_body
+frappe.email
+frappe.email.receive
+frappe.email.smtp
\ No newline at end of file
diff --git a/frappe/docs/current/api/frappe.__init__.html b/frappe/docs/current/api/frappe.__init__.html
new file mode 100644
index 0000000000..25caecf4b5
--- /dev/null
+++ b/frappe/docs/current/api/frappe.__init__.html
@@ -0,0 +1,1681 @@
+
+
+
+
+
Introduction globals attached to frappe module
++ some utility functions that should probably be moved
+
+
+
+
+
+
+
+
+
+ frappe._
+ (msg, lang=None)
+
+
Returns translated string in current lang, if exists.
+
+
+
+
+
+
+
+
Class _dict
+
+
Inherits from __builtin__.dict
+
+
dict like object that exposes keys as attributes
+
+
+
+
+
+
+
+
+
+ __getattr__
+ (self, key)
+
+
+
+
+
+
+
+
+
+
+
+ __getstate__
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ __setattr__
+ (self, key, value)
+
+
+
+
+
+
+
+
+
+
+
+ __setstate__
+ (self, d)
+
+
+
+
+
+
+
+
+
+
+
+ copy
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ update
+ (self, d)
+
+
update and return self -- the missing dict feature in python
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.add_version
+ (doc)
+
+
Insert a new Version of the given document.
+A Version is a JSON dump of the current document state.
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.are_emails_muted
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.as_json
+ (obj, indent=1)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.attach_print
+ (doctype, name, file_name=None, print_format=None, style=None, html=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.build_match_conditions
+ (doctype, as_condition=True)
+
+
Return match (User permissions) for given doctype as list or SQL.
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.cache
+ ()
+
+
Returns memcache connection.
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.call
+ (fn)
+
+
Call a function and match arguments.
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.clear_cache
+ (user=None, doctype=None)
+
+
Clear User , DocType or global cache.
+
+
Parameters:
+
+
+user - If user is given, only user cache is cleared.
+doctype - If doctype is given, only DocType cache is cleared.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.compare
+ (val1, condition, val2)
+
+
Compare two values using frappe.utils.compare
+
+
condition could be:
+- "^"
+- "in"
+- "not in"
+- "="
+- "!="
+- ">"
+- "<"
+- ">="
+- "<="
+- "not None"
+- "None"
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.connect
+ (site=None, db_name=None)
+
+
Connect to site database instance.
+
+
Parameters:
+
+
+site - If site is given, calls frappe.init.
+db_name - Optional. Will use from site_config.json.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.copy_doc
+ (doc, ignore_no_copy=True)
+
+
No_copy fields also get copied.
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.create_folder
+ (path, with_init=False)
+
+
Create a folder in the given path and add an __init__.py file (optional).
+
+
Parameters:
+
+
+path - Folder path.
+with_init - Create __init__.py in the new folder.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.delete_doc
+ (doctype=None, name=None, force=0, ignore_doctypes=None, for_reload=False, ignore_permissions=False, flags=None)
+
+
Delete a document. Calls frappe.model.delete_doc.delete_doc.
+
+
Parameters:
+
+
+doctype - DocType of document to be delete.
+name - Name of document to be delete.
+force - Allow even if document is linked. Warning: This may lead to data integrity errors.
+ignore_doctypes - Ignore if child table is one of these.
+for_reload - Call before_reload trigger before deleting.
+ignore_permissions - Ignore user permissions.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.delete_doc_if_exists
+ (doctype, name)
+
+
Delete document if exists.
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.destroy
+ ()
+
+
Closes connection and releases werkzeug local.
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.errprint
+ (msg)
+
+
Log error. This is sent back as exc in response.
+
+
Parameters:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.format_value
+ (value, df, doc=None, currency=None)
+
+
Format value with given field properties.
+
+
Parameters:
+
+
+value - Value to be formatted.
+df - DocField object with properties fieldtype, options etc.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.generate_hash
+ (txt=None, length=None)
+
+
Generates random hash for given text + current timestamp + random string.
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.get_all
+ (doctype)
+
+
List database query via frappe.model.db_query. Will not check for conditions.
+Parameters are same as frappe.get_list
+
+
Parameters:
+
+
+doctype - DocType on which query is to be made.
+fields - List of fields or *. Default is: ["name"].
+filters - List of filters (see example).
+order_by - Order By e.g. modified desc.
+limit_page_start - Start results at record #. Default 0.
+limit_poge_length - No of records in the page. Default 20.
+
+
+
Example usage:
+
+
# simple dict filter
+frappe.get_all("ToDo", fields=["name", "description"], filters = {"owner":"test@example.com"})
+
+# filter as a list of lists
+frappe.get_all("ToDo", fields=["*"], filters = [["modified", ">", "2014-01-01"]])
+
+# filter as a list of dicts
+frappe.get_all("ToDo", fields=["*"], filters = {"description": ("like", "test%")})
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.get_all_apps
+ (with_frappe=False, with_internal_apps=True, sites_path=None)
+
+
Get list of all apps via sites/apps.txt.
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.get_app_path
+ (app_name)
+
+
Return path of given app.
+
+
Parameters:
+
+
+app - App name.
+*joins - Join additional path elements using os.path.join.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.get_attr
+ (method_string)
+
+
Get python method object from its name.
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.get_doc
+ (arg1, arg2=None)
+
+
Return a frappe.model.document.Document object of the given type and name.
+
+
Parameters:
+
+
+arg1 - DocType name as string or document JSON.
+arg2 - [optional] Document name as string.
+
+
+
Examples:
+
+
# insert a new document
+todo = frappe.get_doc({"doctype":"ToDo", "description": "test"})
+tood.insert()
+
+# open an existing document
+todo = frappe.get_doc("ToDo", "TD0001")
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.get_doctype_app
+ (doctype)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.get_file_items
+ (path, raise_not_found=False, ignore_empty_lines=True)
+
+
Returns items from text file as a list. Ignores empty lines.
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.get_file_json
+ (path)
+
+
Read a file and return parsed JSON object.
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.get_hooks
+ (hook=None, default=None, app_name=None)
+
+
Get hooks via app/hooks.py
+
+
Parameters:
+
+
+hook - Name of the hook. Will gather all hooks for this name and return as a list.
+default - Default if no hook found.
+app_name - Filter by app.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.get_installed_apps
+ (sort=False)
+
+
Get list of installed apps in current site.
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.get_lang_dict
+ (fortype, name=None)
+
+
Returns the translated language dict for the given type and name.
+
+
Parameters:
+
+
+fortype - must be one of doctype, page, report, include, jsfile, boot
+name - name of the document for which assets are to be returned.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.get_last_doc
+ (doctype)
+
+
Get last created document of this type.
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.get_list
+ (doctype)
+
+
List database query via frappe.model.db_query. Will also check for permissions.
+
+
Parameters:
+
+
+doctype - DocType on which query is to be made.
+fields - List of fields or *.
+filters - List of filters (see example).
+order_by - Order By e.g. modified desc.
+limit_page_start - Start results at record #. Default 0.
+limit_poge_length - No of records in the page. Default 20.
+
+
+
Example usage:
+
+
# simple dict filter
+frappe.get_list("ToDo", fields=["name", "description"], filters = {"owner":"test@example.com"})
+
+# filter as a list of lists
+frappe.get_list("ToDo", fields="*", filters = [["modified", ">", "2014-01-01"]])
+
+# filter as a list of dicts
+frappe.get_list("ToDo", fields="*", filters = {"description": ("like", "test%")})
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.get_logger
+ (module=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.get_meta
+ (doctype, cached=True)
+
+
Get frappe.model.meta.Meta instance of given doctype name.
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.get_meta_module
+ (doctype)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.get_module
+ (modulename)
+
+
Returns a module object for given Python module name using importlib.import_module.
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.get_module_list
+ (app_name)
+
+
Get list of modules for given all via app/modules.txt.
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.get_module_path
+ (module)
+
+
Get the path of the given module name.
+
+
Parameters:
+
+
+module - Module name.
+*joins - Join additional path elements using os.path.join.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.get_precision
+ (doctype, fieldname, currency=None, doc=None)
+
+
Get precision for a given field
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.get_print
+ (doctype, name, print_format=None, style=None, html=None, as_pdf=False)
+
+
Get Print Format for given document.
+
+
Parameters:
+
+
+doctype - DocType of document.
+name - Name of document.
+print_format - Print Format name. Default 'Standard',
+style - Print Format style.
+as_pdf - Return as PDF. Default False.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.get_pymodule_path
+ (modulename)
+
+
Return path of given Python module name.
+
+
Parameters:
+
+
+modulename - Python module name.
+*joins - Join additional path elements using os.path.join.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.get_request_header
+ (key, default=None)
+
+
Return HTTP request header.
+
+
Parameters:
+
+
+key - HTTP header key.
+default - Default value.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.get_roles
+ (username=None)
+
+
Returns roles of current user.
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.get_single
+ (doctype)
+
+
Return a frappe.model.document.Document object of the given Single doctype.
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.get_site_config
+ (sites_path=None, site_path=None)
+
+
Returns site_config.json combined with sites/common_site_config.json.
+site_config is a set of site wide settings like database name, password, email etc.
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.get_site_path
+ ()
+
+
Return path of current site.
+
+
Parameters:
+
+
+*joins - Join additional path elements using os.path.join.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.get_test_records
+ (doctype)
+
+
Returns list of objects from test_records.json in the given doctype's folder.
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.get_traceback
+ ()
+
+
Returns error traceback.
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.get_user
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.get_value
+ ()
+
+
Returns a document property or list of properties.
+
+
Alias for frappe.db.get_value
+
+
Parameters:
+
+
+doctype - DocType name.
+filters - Filters like {"x":"y"} or name of the document. None if Single DocType.
+fieldname - Column name.
+ignore - Don't raise exception if table, column is missing.
+as_dict - Return values as dict.
+debug - Print query in error log.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.has_permission
+ (doctype, ptype=read, doc=None, user=None, verbose=False, throw=False)
+
+
Raises frappe.PermissionError if not permitted.
+
+
Parameters:
+
+
+doctype - DocType for which permission is to be check.
+ptype - Permission type (read, write, create, submit, cancel, amend). Default: read.
+doc - [optional] Checks User permissions for given doc.
+user - [optional] Check for given user. Default: current user.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.has_website_permission
+ (doctype, ptype=read, doc=None, user=None, verbose=False)
+
+
Raises frappe.PermissionError if not permitted.
+
+
Parameters:
+
+
+doctype - DocType for which permission is to be check.
+ptype - Permission type (read, write, create, submit, cancel, amend). Default: read.
+doc - Checks User permissions for given doc.
+user - [optional] Check for given user. Default: current user.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.import_doc
+ (path, ignore_links=False, ignore_insert=False, insert=False)
+
+
Import a file using Data Import Tool.
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.init
+ (site, sites_path=None)
+
+
Initialize frappe for the current site. Reset thread locals frappe.local
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.is_table
+ (doctype)
+
+
Returns True if istable property (indicating child Table) is set for given DocType.
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.local_cache
+ (namespace, key, generator, regenerate_if_none=False)
+
+
A key value store for caching within a request
+
+
Parameters:
+
+
+namespace - frappe.local.cache[namespace]
+key - frappe.local.cache[namespace][key] used to retrieve value
+generator - method to generate a value if not found in store
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.log
+ (msg)
+
+
Add to debug_log.
+
+
Parameters:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.make_property_setter
+ (args, ignore_validate=False, validate_fields_for_doctype=True)
+
+
Create a new Property Setter (for overriding DocType and DocField properties).
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.msgprint
+ (msg, small=0, raise_exception=0, as_table=False)
+
+
Print a message to the user (via HTTP response).
+Messages are sent in the __server_messages property in the
+response JSON and shown in a pop-up / modal.
+
+
Parameters:
+
+
+msg - Message.
+small - [optional] Show as a floating message in the footer.
+raise_exception - [optional] Raise given exception and show message.
+as_table - [optional] If msg is a list of lists, render as HTML table.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.new_doc
+ (doctype, parent_doc=None, parentfield=None, as_dict=False)
+
+
Returns a new document of the given DocType with defaults set.
+
+
Parameters:
+
+
+doctype - DocType of the new document.
+parent_doc - [optional] add to parent document.
+parentfield - [optional] add against this parentfield.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.only_for
+ (roles)
+
+
Raise frappe.PermissionError if the user does not have any of the given Roles .
+
+
Parameters:
+
+
+roles - List of roles to check.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.publish_realtime
+ ()
+
+
Publish real-time updates
+
+
Parameters:
+
+
+event - Event name, like task_progress etc.
+message - JSON message object. For async must contain task_id
+room - Room in which to publish update (default entire site)
+user - Transmit to user
+doctype - Transmit to doctype, docname
+docname - Transmit to doctype, docname
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.read_file
+ (path, raise_not_found=False)
+
+
Open a file and return its content as Unicode.
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.reload_doc
+ (module, dt=None, dn=None, force=False)
+
+
Reload Document from model ([module]/[doctype]/[name]/[name].json) files.
+
+
Parameters:
+
+
+module - Module name.
+dt - DocType name.
+dn - Document name.
+force - Reload even if modified timestamp matches.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.reload_doctype
+ (doctype, force=False)
+
+
Reload DocType from model ([module]/[doctype]/[name]/[name].json) files.
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.rename_doc
+ (doctype, old, new, debug=0, force=False, merge=False, ignore_permissions=False)
+
+
Rename a document. Calls frappe.model.rename_doc.rename_doc
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.reset_metadata_version
+ ()
+
+
Reset metadata_version (Client (Javascript) build ID) hash.
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.respond_as_web_page
+ (title, html, success=None, http_status_code=None)
+
+
Send response as a web page with a message rather than JSON. Used to show permission errors etc.
+
+
Parameters:
+
+
+title - Page title and heading.
+message - Message to be shown.
+success - Alert message.
+http_status_code - HTTP status code.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.scrub
+ (txt)
+
+
Returns sluggified string. e.g. Sales Order becomes sales_order.
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.sendmail
+ (recipients=(), sender=, subject=No Subject, message=No Message, as_markdown=False, bulk=False, reference_doctype=None, reference_name=None, unsubscribe_method=None, unsubscribe_params=None, unsubscribe_message=None, attachments=None, content=None, doctype=None, name=None, reply_to=None, cc=(), show_as_cc=(), message_id=None, as_bulk=False, send_after=None, expose_recipients=False, bulk_priority=1)
+
+
Send email using user's default Email Account or global default Email Account .
+
+
Parameters:
+
+
+recipients - List of recipients.
+sender - Email sender. Default is current user.
+subject - Email Subject.
+message - (or content) Email Content.
+as_markdown - Convert content markdown to HTML.
+bulk - Send via scheduled email sender Bulk Email . Don't send immediately.
+bulk_priority - Priority for bulk email, default 1.
+reference_doctype - (or doctype) Append as communication to this DocType.
+reference_name - (or name) Append as communication to this document name.
+unsubscribe_method - Unsubscribe url with options email, doctype, name. e.g. /api/method/unsubscribe
+unsubscribe_params - Unsubscribe paramaters to be loaded on the unsubscribe_method [optional] (dict).
+attachments - List of attachments.
+reply_to - Reply-To email id.
+message_id - Used for threading. If a reply is received to this email, Message-Id is sent back as In-Reply-To in received email.
+send_after - Send after the given datetime.
+expose_recipients - Display all recipients in the footer message - "This email was sent to"
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.set_user
+ (username)
+
+
Set current user.
+
+
Parameters:
+
+
+username - User name to set as current user.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.set_user_lang
+ (user, user_language=None)
+
+
Guess and set user language for the session. frappe.local.lang
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.set_value
+ (doctype, docname, fieldname, value)
+
+
Set document value. Calls frappe.client.set_value
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.setup_module_map
+ ()
+
+
Rebuild map of all modules (internal).
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.throw
+ (msg, exc=)
+
+
Throw execption and show message (msgprint).
+
+
Parameters:
+
+
+msg - Message.
+exc - Exception class. Default frappe.ValidationError
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.unscrub
+ (txt)
+
+
Returns titlified string. e.g. sales_order becomes Sales Order.
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.whitelist
+ (allow_guest=False, xss_safe=False)
+
+
Decorator for whitelisting a function and making it accessible via HTTP.
+Standard request will be /api/method/[path.to.method]
+
+
Parameters:
+
+
+allow_guest - Allow non logged-in user to access this method.
+
+
+
Use as:
+
+
@frappe.whitelist()
+def myfunc(param1, param2):
+ pass
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/frappe.__version__.html b/frappe/docs/current/api/frappe.__version__.html
new file mode 100644
index 0000000000..372f353ff5
--- /dev/null
+++ b/frappe/docs/current/api/frappe.__version__.html
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/frappe.api.html b/frappe/docs/current/api/frappe.api.html
new file mode 100644
index 0000000000..15dd21de86
--- /dev/null
+++ b/frappe/docs/current/api/frappe.api.html
@@ -0,0 +1,53 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.api.handle
+ ()
+
+
Handler for /api methods
+
+
Examples:
+
+
/api/method/{methodname} will call a whitelisted method
+
+
/api/resource/{doctype} will query a table
+ examples:
+ - ?fields=["name", "owner"]
+ - ?filters=[["Task", "name", "like", "%005"]]
+ - ?limit_start=0
+ - ?limit_page_length=20
+
+
/api/resource/{doctype}/{name} will point to a resource
+ GET will return doclist
+ POST will insert
+ PUT will update
+ DELETE will delete
+
+
/api/resource/{doctype}/{name}?run_method={method} will run a whitelisted controller method
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/frappe.app.html b/frappe/docs/current/api/frappe.app.html
new file mode 100644
index 0000000000..7f5911b2ff
--- /dev/null
+++ b/frappe/docs/current/api/frappe.app.html
@@ -0,0 +1,123 @@
+
+
+
+
+
+
+
+
+
Class RequestContext
+
+
Inherits from __builtin__.object
+
+
+
+
+
+
+
+
+
+
+ __enter__
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ __exit__
+ (self, type, value, traceback)
+
+
+
+
+
+
+
+
+
+
+
+ __init__
+ (self, environ)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.app.init_site
+ (request)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.app.make_form_dict
+ (request)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.app.serve
+ (port=8000, profile=False, site=None, sites_path=.)
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/frappe.async.html b/frappe/docs/current/api/frappe.async.html
new file mode 100644
index 0000000000..61c74b5f1e
--- /dev/null
+++ b/frappe/docs/current/api/frappe.async.html
@@ -0,0 +1,394 @@
+
+
+
+
+
+
+
+
+
Class FileAndRedisStream
+
+
Inherits from __builtin__.file
+
+
+
+
+
+
+
+
+
+
+ __init__
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ write
+ (self, data)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.async.can_subscribe_doc
+
+
+
+
+ frappe.async.can_subscribe_doc
+ (doctype, docname, sid)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.async.emit_via_redis
+ (event, message, room)
+
+
Publish real-time updates via redis
+
+
Parameters:
+
+
+event - Event name, like task_progress etc.
+message - JSON message object. For async must contain task_id
+room - name of the room
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.async.get_doc_room
+ (doctype, docname)
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.async.get_pending_tasks_for_doc
+
+
+
+
+ frappe.async.get_pending_tasks_for_doc
+ (doctype, docname)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.async.get_redis_server
+ ()
+
+
Returns memcache connection.
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.async.get_site_room
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.async.get_std_streams
+ (task_id)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.async.get_task_log_file_path
+ (task_id, stream_type)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.async.get_task_progress_room
+ ()
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.async.get_task_status
+
+
+
+
+ frappe.async.get_task_status
+ (task_id)
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.async.get_user_info
+
+
+
+
+ frappe.async.get_user_info
+ (sid)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.async.get_user_room
+ (user)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.async.handler
+ (f)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.async.is_file_old
+ (file_path)
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.async.ping
+
+
+
+
+ frappe.async.ping
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.async.publish_realtime
+ (event=None, message=None, room=None, user=None, doctype=None, docname=None, now=False)
+
+
Publish real-time updates
+
+
Parameters:
+
+
+event - Event name, like task_progress etc. that will be handled by the client (default is task_progress if within task or global)
+message - JSON message object. For async must contain task_id
+room - Room in which to publish update (default entire site)
+user - Transmit to user
+doctype - Transmit to doctype, docname
+docname - Transmit to doctype, docname
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.async.put_log
+ (line_no, line, task_id=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.async.remove_old_task_logs
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.async.set_task_status
+ (task_id, status, response=None)
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/frappe.auth.html b/frappe/docs/current/api/frappe.auth.html
new file mode 100644
index 0000000000..891c9f4b1f
--- /dev/null
+++ b/frappe/docs/current/api/frappe.auth.html
@@ -0,0 +1,485 @@
+
+
+
+
+
+
+
+
+
Class CookieManager
+
+
+
+
+
+
+
+
+
+
+ __init__
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ delete_cookie
+ (self, to_delete)
+
+
+
+
+
+
+
+
+
+
+
+ flush_cookies
+ (self, response)
+
+
+
+
+
+
+
+
+
+
+
+ init_cookies
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ set_cookie
+ (self, key, value, expires=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
Class HTTPRequest
+
+
+
+
+
+
+
+
+
+
+ __init__
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ connect
+ (self, ac_name=None)
+
+
connect to db, from acname or db name
+
+
+
+
+
+
+
+
+
+
+ get_db_name
+ (self)
+
+
get database name from conf
+
+
+
+
+
+
+
+
+
+
+ set_lang
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ validate_csrf_token
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+
+
Class LoginManager
+
+
+
+
+
+
+
+
+
+
+ __init__
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ authenticate
+ (self, user=None, pwd=None)
+
+
+
+
+
+
+
+
+
+
+
+ check_if_enabled
+ (self, user)
+
+
raise exception if user not enabled
+
+
+
+
+
+
+
+
+
+
+ check_password
+ (self, user, pwd)
+
+
+
+
+
+
+
+
+
+
+
+ clear_active_sessions
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ clear_cookies
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ fail
+ (self, message)
+
+
+
+
+
+
+
+
+
+
+
+ login
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ login_as
+ (self, user)
+
+
+
+
+
+
+
+
+
+
+
+ login_as_guest
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ logout
+ (self, arg=, user=None)
+
+
+
+
+
+
+
+
+
+
+
+ make_session
+ (self, resume=False)
+
+
+
+
+
+
+
+
+
+
+
+ post_login
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ run_trigger
+ (self, event=on_login)
+
+
+
+
+
+
+
+
+
+
+
+ set_user_info
+ (self, resume=False)
+
+
+
+
+
+
+
+
+
+
+
+ validate_hour
+ (self)
+
+
check if user is logging in during restricted hours
+
+
+
+
+
+
+
+
+
+
+ validate_ip_address
+ (self)
+
+
check if IP Address is valid
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.auth._update_password
+ (user, password)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.auth.clear_cookies
+ ()
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.auth.get_logged_user
+
+
+
+
+ frappe.auth.get_logged_user
+ ()
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/frappe.boot.html b/frappe/docs/current/api/frappe.boot.html
new file mode 100644
index 0000000000..9dcd1661d0
--- /dev/null
+++ b/frappe/docs/current/api/frappe.boot.html
@@ -0,0 +1,178 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.boot.add_home_page
+ (bootinfo, docs)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.boot.add_timezone_info
+ (bootinfo)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.boot.get_allowed_pages
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.boot.get_bootinfo
+ ()
+
+
build and return boot info
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.boot.get_fullnames
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.boot.get_user
+ (bootinfo)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.boot.load_conf_settings
+ (bootinfo)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.boot.load_print
+ (bootinfo, doclist)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.boot.load_print_css
+ (bootinfo, print_settings)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.boot.load_translations
+ (bootinfo)
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/frappe.build.html b/frappe/docs/current/api/frappe.build.html
new file mode 100644
index 0000000000..f77d3c7cd2
--- /dev/null
+++ b/frappe/docs/current/api/frappe.build.html
@@ -0,0 +1,178 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.build.build
+ (no_compress=False, verbose=False)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.build.bundle
+ (no_compress, make_copy=False, verbose=False)
+
+
concat / minify js files
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.build.compile_less
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.build.files_dirty
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.build.get_build_maps
+ ()
+
+
get all build.jsons with absolute paths
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.build.html_to_js_template
+ (path, content)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.build.make_asset_dirs
+ (make_copy=False)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.build.pack
+ (target, sources, no_compress, verbose)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.build.setup
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.build.watch
+ (no_compress)
+
+
watch and rebuild if necessary
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/frappe.celery_app.html b/frappe/docs/current/api/frappe.celery_app.html
new file mode 100644
index 0000000000..c1b605d4fc
--- /dev/null
+++ b/frappe/docs/current/api/frappe.celery_app.html
@@ -0,0 +1,261 @@
+
+
+
+
+
+
+
+
+
Class AsyncTaskRouter
+
+
Inherits from __builtin__.object
+
+
+
+
+
+
+
+
+
+
+ route_for_task
+ (self, task, args=None, kwargs=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
Class MonitorThread
+
+
Inherits from __builtin__.object
+
+
Thread manager for monitoring celery events
+
+
+
+
+
+
+
+
+
+ __init__
+ (self, celery_app, interval=1)
+
+
+
+
+
+
+
+
+
+
+
+ catchall
+ (self, event)
+
+
+
+
+
+
+
+
+
+
+
+ run
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+
+
Class SiteRouter
+
+
Inherits from __builtin__.object
+
+
+
+
+
+
+
+
+
+
+ route_for_task
+ (self, task, args=None, kwargs=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.celery_app.celery_task
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.celery_app.get_beat_schedule
+ (conf)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.celery_app.get_celery
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.celery_app.get_celery_app
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.celery_app.get_queue
+ (site, prefix=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.celery_app.get_site_config
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.celery_app.make_async_task
+ (args)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.celery_app.run_test
+ ()
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/frappe.client.html b/frappe/docs/current/api/frappe.client.html
new file mode 100644
index 0000000000..43248c3576
--- /dev/null
+++ b/frappe/docs/current/api/frappe.client.html
@@ -0,0 +1,288 @@
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.client.bulk_update
+
+
+
+
+ frappe.client.bulk_update
+ (docs)
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.client.cancel
+
+
+
+
+ frappe.client.cancel
+ (doctype, name)
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.client.delete
+
+
+
+
+ frappe.client.delete
+ (doctype, name)
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.client.get
+
+
+
+
+ frappe.client.get
+ (doctype, name=None, filters=None)
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.client.get_js
+
+
+
+
+ frappe.client.get_js
+ (src)
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.client.get_list
+
+
+
+
+ frappe.client.get_list
+ (doctype, fields=None, filters=None, order_by=None, limit_start=None, limit_page_length=20)
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.client.get_value
+
+
+
+
+ frappe.client.get_value
+ (doctype, fieldname, filters=None, as_dict=True, debug=False)
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.client.has_permission
+
+
+
+
+ frappe.client.has_permission
+ (doctype, docname, perm_type=read)
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.client.insert
+
+
+
+
+ frappe.client.insert
+ (doc=None)
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.client.make_width_property_setter
+
+
+
+
+ frappe.client.make_width_property_setter
+ (doc)
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.client.rename_doc
+
+
+
+
+ frappe.client.rename_doc
+ (doctype, old_name, new_name, merge=False)
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.client.save
+
+
+
+
+ frappe.client.save
+ (doc)
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.client.set_default
+
+
+
+
+ frappe.client.set_default
+ (key, value, parent=None)
+
+
set a user default value
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.client.set_value
+
+
+
+
+ frappe.client.set_value
+ (doctype, name, fieldname, value)
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.client.submit
+
+
+
+
+ frappe.client.submit
+ (doc)
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/frappe.commands.html b/frappe/docs/current/api/frappe.commands.html
new file mode 100644
index 0000000000..2795b95594
--- /dev/null
+++ b/frappe/docs/current/api/frappe.commands.html
@@ -0,0 +1,162 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.commands._build_docs_once
+ (site, app, docs_version, target, local, only_content_updated=False)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.commands._is_scheduler_enabled
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.commands._new_site
+ (db_name, site, mariadb_root_username=None, mariadb_root_password=None, admin_password=None, verbose=False, install_apps=None, source_sql=None, force=False, reinstall=False)
+
+
Install a new Frappe site
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.commands.call_command
+ (cmd, context)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.commands.get_single_site
+ (context)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.commands.move
+ (dest_dir, site)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.commands.pass_context
+ (f)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.commands.prepare_for_update
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.commands.use
+ (site, sites_path=.)
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/frappe.database.html b/frappe/docs/current/api/frappe.database.html
new file mode 100644
index 0000000000..ee777df3e3
--- /dev/null
+++ b/frappe/docs/current/api/frappe.database.html
@@ -0,0 +1,938 @@
+
+
+
+
+
+
+
+
+
Class Database
+
+
Open a database connection with the given parmeters, if use_default is True, use the
+login details from conf.py. This is called by the request handler and is accessible using
+the db global variable. the sql method is also global to run queries
+
+
+
+
+
+
+
+
+
+ __init__
+ (self, host=None, user=None, password=None, ac_name=None, use_default=0)
+
+
+
+
+
+
+
+
+
+
+
+ _get_value_for_many_names
+ (self, doctype, names, field, debug=False)
+
+
+
+
+
+
+
+
+
+
+
+ _get_values_from_table
+ (self, fields, filters, doctype, as_dict, debug, order_by=None, update=None)
+
+
+
+
+
+
+
+
+
+
+
+ a_row_exists
+ (self, doctype)
+
+
Returns True if atleast one row exists.
+
+
+
+
+
+
+
+
+
+
+ add_default
+ (self, key, val, parent=__default, parenttype=None)
+
+
Append a default value for a key, there can be multiple default values for a particular key.
+
+
+
+
+
+
+
+
+
+
+ add_index
+ (self, doctype, fields, index_name=None)
+
+
Creates an index with given fields if not already created.
+Index name will be fieldname1_fieldname2_index
+
+
+
+
+
+
+
+
+
+
+ add_unique
+ (self, doctype, fields, constraint_name=None)
+
+
+
+
+
+
+
+
+
+
+
+ begin
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ build_conditions
+ (self, filters)
+
+
Convert filters sent as dict, lists to SQL conditions. filter's key
+is passed by map function, build conditions like:
+
+
+ifnull(fieldname, default_value) = %(fieldname)s
+fieldname [=, !=, >, >=, <, <=] %(fieldname)s
+
+
+
+
+
+
+
+
+
+
+
+ check_transaction_status
+ (self, query)
+
+
Raises exception if more than 20,000 INSERT, UPDATE queries are
+executed in one transaction. This is to ensure that writes are always flushed otherwise this
+could cause the system to hang.
+
+
+
+
+
+
+
+
+
+
+ close
+ (self)
+
+
Close database connection.
+
+
+
+
+
+
+
+
+
+
+ commit
+ (self)
+
+
Commit current transaction. Calls SQL COMMIT.
+
+
+
+
+
+
+
+
+
+
+ connect
+ (self)
+
+
Connects to a database as set in site_config.json.
+
+
+
+
+
+
+
+
+
+
+ convert_to_lists
+ (self, res, formatted=0, as_utf8=0)
+
+
Convert tuple output to lists (internal).
+
+
+
+
+
+
+
+
+
+
+ convert_to_simple_type
+ (self, v, formatted=0)
+
+
Format date, time, longint values.
+
+
+
+
+
+
+
+
+
+
+ convert_to_utf8
+ (self, res, formatted=0)
+
+
Encode result as UTF-8.
+
+
+
+
+
+
+
+
+
+
+ count
+ (self, dt, filters=None, debug=False)
+
+
Returns COUNT(*) for given DocType and filters.
+
+
+
+
+
+
+
+
+
+
+ escape
+ (self, s, percent=True)
+
+
Excape quotes and percent in given string.
+
+
+
+
+
+
+
+
+
+
+ exists
+ (self, dt, dn=None)
+
+
Returns true if document exists.
+
+
Parameters:
+
+
+dt - DocType name.
+dn - Document name or filter dict.
+
+
+
+
+
+
+
+
+
+
+
+ explain_query
+ (self, query, values=None)
+
+
Print EXPLAIN in error log.
+
+
+
+
+
+
+
+
+
+
+ fetch_as_dict
+ (self, formatted=0, as_utf8=0)
+
+
Internal. Converts results to dict.
+
+
+
+
+
+
+
+
+
+
+ field_exists
+ (self, dt, fn)
+
+
Return true of field exists.
+
+
+
+
+
+
+
+
+
+
+ get
+ (self, doctype, filters=None, as_dict=True, cache=False)
+
+
Returns get_value with fieldname='*'
+
+
+
+
+
+
+
+
+
+
+ get_all
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ get_creation_count
+ (self, doctype, minutes)
+
+
Get count of records created in the last x minutes
+
+
+
+
+
+
+
+
+
+
+ get_db_login
+ (self, ac_name)
+
+
+
+
+
+
+
+
+
+
+
+ get_default
+ (self, key, parent=__default)
+
+
Returns default value as a list if multiple or single
+
+
+
+
+
+
+
+
+
+
+ get_defaults
+ (self, key=None, parent=__default)
+
+
+
+
+
+
+
+
+
+
+
+ get_description
+ (self)
+
+
Returns result metadata.
+
+
+
+
+
+
+
+
+
+
+ get_global
+ (self, key, user=__global)
+
+
Returns a global key value.
+
+
+
+
+
+
+
+
+
+
+ get_list
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ get_single_value
+ (self, doctype, fieldname, cache=False)
+
+
Get property of Single DocType. Cache locally by default
+
+
+
+
+
+
+
+
+
+
+ get_singles_dict
+ (self, doctype)
+
+
Get Single DocType as dict.
+
+
+
+
+
+
+
+
+
+
+ get_singles_value
+ (self)
+
+
Alias for getsingle value
+
+
+
+
+
+
+
+
+
+
+ get_table_columns
+ (self, doctype)
+
+
Returns list of column names from given doctype.
+
+
+
+
+
+
+
+
+
+
+ get_tables
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ get_temp
+ (self, key)
+
+
Return the temperory value and delete it.
+
+
+
+
+
+
+
+
+
+
+ get_value
+ (self, doctype, filters=None, fieldname=name, ignore=None, as_dict=False, debug=False, cache=False)
+
+
Returns a document property or list of properties.
+
+
Parameters:
+
+
+doctype - DocType name.
+filters - Filters like {"x":"y"} or name of the document. None if Single DocType.
+fieldname - Column name.
+ignore - Don't raise exception if table, column is missing.
+as_dict - Return values as dict.
+debug - Print query in error log.
+
+
+
Example:
+
+
# return first customer starting with a
+frappe.db.get_value("Customer", {"name": ("like a%")})
+
+# return last login of **User** `test@example.com`
+frappe.db.get_value("User", "test@example.com", "last_login")
+
+last_login, last_ip = frappe.db.get_value("User", "test@example.com",
+ ["last_login", "last_ip"])
+
+# returns default date_format
+frappe.db.get_value("System Settings", None, "date_format")
+
+
+
+
+
+
+
+
+
+
+
+ get_values
+ (self, doctype, filters=None, fieldname=name, ignore=None, as_dict=False, debug=False, order_by=None, update=None, cache=False)
+
+
Returns multiple document properties.
+
+
Parameters:
+
+
+doctype - DocType name.
+filters - Filters like {"x":"y"} or name of the document.
+fieldname - Column name.
+ignore - Don't raise exception if table, column is missing.
+as_dict - Return values as dict.
+debug - Print query in error log.
+
+
+
Example:
+
+
# return first customer starting with a
+customers = frappe.db.get_values("Customer", {"name": ("like a%")})
+
+# return last login of **User** `test@example.com`
+user = frappe.db.get_values("User", "test@example.com", "*")[0]
+
+
+
+
+
+
+
+
+
+
+
+ get_values_from_single
+ (self, fields, filters, doctype, as_dict=False, debug=False, update=None)
+
+
Get values from tabSingles (Single DocTypes) (internal).
+
+
Parameters:
+
+
+fields - List of fields,
+filters - Filters (dict).
+doctype - DocType name.
+
+
+
+
+
+
+
+
+
+
+
+ has_column
+ (self, doctype, column)
+
+
Returns True if column exists in database.
+
+
+
+
+
+
+
+
+
+
+ needs_formatting
+ (self, result, formatted)
+
+
Returns true if the first row in the result has a Date, Datetime, Long Int.
+
+
+
+
+
+
+
+
+
+
+ rollback
+ (self)
+
+
ROLLBACK current transaction.
+
+
+
+
+
+
+
+
+
+
+ set
+ (self, doc, field, val)
+
+
Set value in document. Avoid
+
+
+
+
+
+
+
+
+
+
+ set_default
+ (self, key, val, parent=__default, parenttype=None)
+
+
Sets a global / user default value.
+
+
+
+
+
+
+
+
+
+
+ set_global
+ (self, key, val, user=__global)
+
+
Save a global key value. Global values will be automatically set if they match fieldname.
+
+
+
+
+
+
+
+
+
+
+ set_temp
+ (self, value)
+
+
Set a temperory value and return a key.
+
+
+
+
+
+
+
+
+
+
+ set_value
+ (self, dt, dn, field, val, modified=None, modified_by=None, update_modified=True, debug=False)
+
+
Set a single value in the database, do not call the ORM triggers
+but update the modified timestamp (unless specified not to).
+
+
Warning: this function will not call Document events and should be avoided in normal cases.
+
+
Parameters:
+
+
+dt - DocType name.
+dn - Document name.
+field - Property / field name.
+value - Value to be updated.
+modified - Use this as the modified timestamp.
+modified_by - Set this user as modified_by.
+update_modified - default True. Set as false, if you don't want to update the timestamp.
+debug - Print the query in the developer / js console.
+
+
+
+
+
+
+
+
+
+
+
+ sql
+ (self, query, values=(), as_dict=0, as_list=0, formatted=0, debug=0, ignore_ddl=0, as_utf8=0, auto_commit=0, update=None)
+
+
Execute a SQL query and fetch all rows.
+
+
Parameters:
+
+
+query - SQL query.
+values - List / dict of values to be escaped and substituted in the query.
+as_dict - Return as a dictionary.
+as_list - Always return as a list.
+formatted - Format values like date etc.
+debug - Print query and EXPLAIN in debug log.
+ignore_ddl - Catch exception if table, column missing.
+as_utf8 - Encode values as UTF 8.
+auto_commit - Commit after executing the query.
+update - Update this dict to all rows (if returned as_dict).
+
+
+
Examples:
+
+
# return customer names as dicts
+frappe.db.sql("select name from tabCustomer", as_dict=True)
+
+# return names beginning with a
+frappe.db.sql("select name from tabCustomer where name like %s", "a%")
+
+# values as dict
+frappe.db.sql("select name from tabCustomer where name like %(name)s and owner=%(owner)s",
+ {"name": "a%", "owner":"test@example.com"})
+
+
+
+
+
+
+
+
+
+
+
+ sql_ddl
+ (self, query, values=(), debug=False)
+
+
Commit and execute a query. DDL (Data Definition Language) queries that alter schema
+autocommit in MariaDB.
+
+
+
+
+
+
+
+
+
+
+ sql_list
+ (self, query, values=(), debug=False)
+
+
Return data as list of single elements (first column).
+
+
Example:
+
+
# doctypes = ["DocType", "DocField", "User", ...]
+doctypes = frappe.db.sql_list("select name from DocType")
+
+
+
+
+
+
+
+
+
+
+
+ table_exists
+ (self, tablename)
+
+
Returns True if table exists.
+
+
+
+
+
+
+
+
+
+
+ touch
+ (self, doctype, docname)
+
+
Update the modified timestamp of this document.
+
+
+
+
+
+
+
+
+
+
+ update
+ (self)
+
+
Update multiple values. Alias for set_value.
+
+
+
+
+
+
+
+
+
+
+ use
+ (self, db_name)
+
+
+
+
+
+
+
+
+
+
+
+ validate_query
+ (self, q)
+
+
Throw exception for dangerous queries: ALTER, DROP, TRUNCATE if not Administrator.
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/frappe.defaults.html b/frappe/docs/current/api/frappe.defaults.html
new file mode 100644
index 0000000000..30913632f1
--- /dev/null
+++ b/frappe/docs/current/api/frappe.defaults.html
@@ -0,0 +1,310 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.defaults._clear_cache
+ (parent)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.defaults.add_default
+ (key, value, parent, parenttype=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.defaults.add_global_default
+ (key, value)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.defaults.add_user_default
+ (key, value, user=None, parenttype=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.defaults.build_user_permissions
+ (user)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.defaults.clear_cache
+ (user=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.defaults.clear_default
+ (key=None, value=None, parent=None, name=None, parenttype=None)
+
+
Clear a default value by any of the given parameters and delete caches.
+
+
Parameters:
+
+
+key - Default key.
+value - Default value.
+parent - User name, or __global, __default.
+name - Default ID.
+parenttype - Clear defaults table for a particular type e.g. User .
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.defaults.clear_user_default
+ (key, user=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.defaults.get_defaults
+ (user=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.defaults.get_defaults_for
+ (parent=__default)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.defaults.get_global_default
+ (key)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.defaults.get_user_default
+ (key, user=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.defaults.get_user_default_as_list
+ (key, user=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.defaults.get_user_permissions
+ (user=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.defaults.set_default
+ (key, value, parent, parenttype=__default)
+
+
Override or add a default value.
+Adds default value in table tabDefaultValue.
+
+
Parameters:
+
+
+key - Default key.
+value - Default value.
+parent - Usually, User to whom the default belongs.
+parenttype - [optional] default is __default.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.defaults.set_global_default
+ (key, value)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.defaults.set_user_default
+ (key, value, user=None, parenttype=None)
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/frappe.exceptions.html b/frappe/docs/current/api/frappe.exceptions.html
new file mode 100644
index 0000000000..98616a0b3b
--- /dev/null
+++ b/frappe/docs/current/api/frappe.exceptions.html
@@ -0,0 +1,483 @@
+
+
+
+
+
+
+
+
+
Class AppNotInstalledError
+
+
Inherits from frappe.exceptions.ValidationError
+
+
+
+
+
+
+
+
+
+
+
+
Class AuthenticationError
+
+
Inherits from exceptions.Exception
+
+
+
+
+
+
+
+
+
+
+
+
Class CSRFTokenError
+
+
Inherits from exceptions.Exception
+
+
+
+
+
+
+
+
+
+
+
+
Class CancelledLinkError
+
+
Inherits from frappe.exceptions.LinkValidationError
+
+
+
+
+
+
+
+
+
+
+
+
Class CannotChangeConstantError
+
+
Inherits from frappe.exceptions.ValidationError
+
+
+
+
+
+
+
+
+
+
+
+
Class CharacterLengthExceededError
+
+
Inherits from frappe.exceptions.ValidationError
+
+
+
+
+
+
+
+
+
+
+
+
Class DataError
+
+
Inherits from frappe.exceptions.ValidationError
+
+
+
+
+
+
+
+
+
+
+
+
Class DocstatusTransitionError
+
+
Inherits from frappe.exceptions.ValidationError
+
+
+
+
+
+
+
+
+
+
+
+
Class DoesNotExistError
+
+
Inherits from frappe.exceptions.ValidationError
+
+
+
+
+
+
+
+
+
+
+
+
Class DuplicateEntryError
+
+
Inherits from frappe.exceptions.NameError
+
+
+
+
+
+
+
+
+
+
+
+
Class EmptyTableError
+
+
Inherits from frappe.exceptions.ValidationError
+
+
+
+
+
+
+
+
+
+
+
+
Class InvalidEmailAddressError
+
+
Inherits from frappe.exceptions.ValidationError
+
+
+
+
+
+
+
+
+
+
+
+
Class InvalidSignatureError
+
+
Inherits from frappe.exceptions.ValidationError
+
+
+
+
+
+
+
+
+
+
+
+
Class InvalidStatusError
+
+
Inherits from frappe.exceptions.ValidationError
+
+
+
+
+
+
+
+
+
+
+
+
Class LinkExistsError
+
+
Inherits from frappe.exceptions.ValidationError
+
+
+
+
+
+
+
+
+
+
+
+
Class LinkValidationError
+
+
Inherits from frappe.exceptions.ValidationError
+
+
+
+
+
+
+
+
+
+
+
+
Class MandatoryError
+
+
Inherits from frappe.exceptions.ValidationError
+
+
+
+
+
+
+
+
+
+
+
+
Class MappingMismatchError
+
+
Inherits from frappe.exceptions.ValidationError
+
+
+
+
+
+
+
+
+
+
+
+
Class NameError
+
+
Inherits from exceptions.Exception
+
+
+
+
+
+
+
+
+
+
+
+
Class OutgoingEmailError
+
+
Inherits from exceptions.Exception
+
+
+
+
+
+
+
+
+
+
+
+
Class PermissionError
+
+
Inherits from exceptions.Exception
+
+
+
+
+
+
+
+
+
+
+
+
Class RateLimitExceededError
+
+
Inherits from frappe.exceptions.ValidationError
+
+
+
+
+
+
+
+
+
+
+
+
Class Redirect
+
+
Inherits from exceptions.Exception
+
+
+
+
+
+
+
+
+
+
+
+
Class SessionStopped
+
+
Inherits from exceptions.Exception
+
+
+
+
+
+
+
+
+
+
+
+
Class TemplateNotFoundError
+
+
Inherits from frappe.exceptions.ValidationError
+
+
+
+
+
+
+
+
+
+
+
+
Class TimestampMismatchError
+
+
Inherits from frappe.exceptions.ValidationError
+
+
+
+
+
+
+
+
+
+
+
+
Class UniqueValidationError
+
+
Inherits from frappe.exceptions.ValidationError
+
+
+
+
+
+
+
+
+
+
+
+
Class UnknownDomainError
+
+
Inherits from exceptions.Exception
+
+
+
+
+
+
+
+
+
+
+
+
Class UnsupportedMediaType
+
+
Inherits from exceptions.Exception
+
+
+
+
+
+
+
+
+
+
+
+
Class UpdateAfterSubmitError
+
+
Inherits from frappe.exceptions.ValidationError
+
+
+
+
+
+
+
+
+
+
+
+
Class ValidationError
+
+
Inherits from exceptions.Exception
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/frappe.frappeclient.html b/frappe/docs/current/api/frappe.frappeclient.html
new file mode 100644
index 0000000000..69073740be
--- /dev/null
+++ b/frappe/docs/current/api/frappe.frappeclient.html
@@ -0,0 +1,399 @@
+
+
+
+
+
+
+
+
+
Class AuthError
+
+
Inherits from exceptions.Exception
+
+
+
+
+
+
+
+
+
+
+
+
Class FrappeClient
+
+
Inherits from __builtin__.object
+
+
+
+
+
+
+
+
+
+
+ __enter__
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ __exit__
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ __init__
+ (self, url, username, password, verify=True)
+
+
+
+
+
+
+
+
+
+
+
+ bulk_update
+ (self, docs)
+
+
+
+
+
+
+
+
+
+
+
+ cancel
+ (self, doctype, name)
+
+
+
+
+
+
+
+
+
+
+
+ delete
+ (self, doctype, name)
+
+
+
+
+
+
+
+
+
+
+
+ get_api
+ (self, method, params={})
+
+
+
+
+
+
+
+
+
+
+
+ get_doc
+ (self, doctype, name=, filters=None, fields=None)
+
+
+
+
+
+
+
+
+
+
+
+ get_list
+ (self, doctype, fields="*", filters=None, limit_start=0, limit_page_length=0)
+
+
Returns list of records of a particular type
+
+
+
+
+
+
+
+
+
+
+ get_request
+ (self, params)
+
+
+
+
+
+
+
+
+
+
+
+ get_value
+ (self, doctype, fieldname=None, filters=None)
+
+
+
+
+
+
+
+
+
+
+
+ insert
+ (self, doc)
+
+
+
+
+
+
+
+
+
+
+
+ login
+ (self, username, password)
+
+
+
+
+
+
+
+
+
+
+
+ logout
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ migrate_doctype
+ (self, doctype, filters=None, update=None, verbose=1, exclude=None, preprocess=None)
+
+
Migrate records from another doctype
+
+
+
+
+
+
+
+
+
+
+ migrate_single
+ (self, doctype)
+
+
+
+
+
+
+
+
+
+
+
+ post_api
+ (self, method, params={})
+
+
+
+
+
+
+
+
+
+
+
+ post_process
+ (self, response)
+
+
+
+
+
+
+
+
+
+
+
+ post_request
+ (self, data)
+
+
+
+
+
+
+
+
+
+
+
+ preprocess
+ (self, params)
+
+
convert dicts, lists to json
+
+
+
+
+
+
+
+
+
+
+ rename_doc
+ (self, doctype, old_name, new_name)
+
+
+
+
+
+
+
+
+
+
+
+ set_value
+ (self, doctype, docname, fieldname, value)
+
+
+
+
+
+
+
+
+
+
+
+ submit
+ (self, doclist)
+
+
+
+
+
+
+
+
+
+
+
+ update
+ (self, doc)
+
+
+
+
+
+
+
+
+
+
+
+
+
Class FrappeException
+
+
Inherits from exceptions.Exception
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/frappe.handler.html b/frappe/docs/current/api/frappe.handler.html
new file mode 100644
index 0000000000..041644794a
--- /dev/null
+++ b/frappe/docs/current/api/frappe.handler.html
@@ -0,0 +1,244 @@
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.handler.async_ping
+
+
+
+
+ frappe.handler.async_ping
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.handler.execute_cmd
+ (cmd, from_async=False)
+
+
execute a request as python module
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.handler.get_async_task_status
+
+
+
+
+ frappe.handler.get_async_task_status
+ (task_id)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.handler.get_attr
+ (cmd)
+
+
get method object from cmd
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.handler.handle
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.handler.is_whitelisted
+ (method)
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.handler.logout
+
+
+
+
+ frappe.handler.logout
+ ()
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.handler.ping
+
+
+
+
+ frappe.handler.ping
+ ()
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.handler.run_custom_method
+
+
+
+
+ frappe.handler.run_custom_method
+ (doctype, name, custom_method)
+
+
cmd=runcustom method&doctype={doctype}&name={name}&custommethod={custom method}
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.handler.runserverobj
+
+
+
+
+ frappe.handler.runserverobj
+ (method, docs=None, dt=None, dn=None, arg=None, args=None)
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.handler.uploadfile
+
+
+
+
+ frappe.handler.uploadfile
+ ()
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.handler.version
+
+
+
+
+ frappe.handler.version
+ ()
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.handler.web_logout
+
+
+
+
+ frappe.handler.web_logout
+ ()
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/frappe.hooks.html b/frappe/docs/current/api/frappe.hooks.html
new file mode 100644
index 0000000000..b895aa923e
--- /dev/null
+++ b/frappe/docs/current/api/frappe.hooks.html
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/frappe.installer.html b/frappe/docs/current/api/frappe.installer.html
new file mode 100644
index 0000000000..777b67487e
--- /dev/null
+++ b/frappe/docs/current/api/frappe.installer.html
@@ -0,0 +1,370 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.installer.add_module_defs
+ (app)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.installer.add_to_installed_apps
+ (app_name, rebuild_website=True)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.installer.check_if_ready_for_barracuda
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.installer.create_auth_table
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.installer.create_database_and_user
+ (force, verbose)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.installer.get_conf_params
+ (db_name=None, db_password=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.installer.get_current_host
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.installer.get_site_config_path
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.installer.import_db_from_sql
+ (source_sql, verbose)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.installer.init_singles
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.installer.install_app
+ (name, verbose=False, set_as_patched=True)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.installer.install_db
+ (root_login=root, root_password=None, db_name=None, source_sql=None, admin_password=None, verbose=True, force=0, site_config=None, reinstall=False)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.installer.make_conf
+ (db_name=None, db_password=None, site_config=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.installer.make_connection
+ (root_login, root_password)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.installer.make_site_config
+ (db_name=None, db_password=None, site_config=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.installer.make_site_dirs
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.installer.post_install
+ (rebuild_website=False)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.installer.remove_app
+ (app_name, dry_run=False)
+
+
Delete app and all linked to the app's module with the app.
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.installer.remove_from_installed_apps
+ (app_name)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.installer.remove_missing_apps
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.installer.set_all_patches_as_completed
+ (app)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.installer.update_site_config
+ (key, value)
+
+
Update a value in site_config
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/frappe.middlewares.html b/frappe/docs/current/api/frappe.middlewares.html
new file mode 100644
index 0000000000..d45f840e47
--- /dev/null
+++ b/frappe/docs/current/api/frappe.middlewares.html
@@ -0,0 +1,61 @@
+
+
+
+
+
+
+
+
+
Class StaticDataMiddleware
+
+
Inherits from werkzeug.wsgi.SharedDataMiddleware
+
+
+
+
+
+
+
+
+
+
+ __call__
+ (self, environ, start_response)
+
+
+
+
+
+
+
+
+
+
+
+ get_directory_loader
+ (self, directory)
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/frappe.permissions.html b/frappe/docs/current/api/frappe.permissions.html
new file mode 100644
index 0000000000..092754c084
--- /dev/null
+++ b/frappe/docs/current/api/frappe.permissions.html
@@ -0,0 +1,332 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.permissions.add_user_permission
+ (doctype, name, user, with_message=False)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.permissions.apply_user_permissions
+ (doctype, ptype, user=None)
+
+
Check if applyuser permissions is checked for a doctype, perm type, user combination
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.permissions.can_export
+ (doctype, raise_exception=False)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.permissions.can_import
+ (doctype, raise_exception=False)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.permissions.can_set_user_permissions
+ (doctype, docname=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.permissions.check_admin_or_system_manager
+ (user=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.permissions.clear_user_permissions_for_doctype
+ (doctype)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.permissions.get_doc_permissions
+ (doc, verbose=False, user=None)
+
+
Returns a dict of evaluated permissions for given doc like {"read":1, "write":1}
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.permissions.get_linked_doctypes
+ (dt)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.permissions.get_role_permissions
+ (meta, user=None, verbose=False)
+
+
Returns dict of evaluated role permissions like {"read": True, "write":False}
+
+
If user permissions are applicable, it adds a dict of user permissions like
+
+
{
+ // user permissions will apply on these rights
+ "apply_user_permissions": {"read": 1, "write": 1},
+
+ // doctypes that will be applicable for each right
+ "user_permission_doctypes": {
+ "read": [
+ // AND between "DocType 1" and "DocType 2"
+ ["DocType 1", "DocType 2"],
+
+ // OR
+
+ ["DocType 3"]
+
+ ]
+ }
+
+ "if_owner": {"read": 1, "write": 1}
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.permissions.get_user_permission_doctypes
+ (user_permission_doctypes, user_permissions)
+
+
returns a list of list like [["User", "Blog Post"], ["User"]]
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.permissions.has_controller_permissions
+ (doc, ptype, user=None)
+
+
Returns controller permissions if defined. None if not defined
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.permissions.has_permission
+ (doctype, ptype=read, doc=None, verbose=False, user=None)
+
+
Returns True if user has permission ptype for given doctype.
+If doc is passed, it also checks user, share and owner permissions.
+
+
Note: if Table DocType is passed, it always returns True.
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.permissions.remove_user_permission
+ (doctype, name, user, default_value_name=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.permissions.reset_perms
+ (doctype)
+
+
Reset permissions for given doctype.
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.permissions.set_user_permission_if_allowed
+ (doctype, name, user, with_message=False)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.permissions.update_share_permissions
+ (role_permissions, doc, user)
+
+
Updates share permissions on role_permissions for given doc, if shared
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.permissions.user_has_permission
+ (doc, verbose=True, user=None, user_permission_doctypes=None)
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/frappe.pythonrc.html b/frappe/docs/current/api/frappe.pythonrc.html
new file mode 100644
index 0000000000..57ab827cc7
--- /dev/null
+++ b/frappe/docs/current/api/frappe.pythonrc.html
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/frappe.sessions.html b/frappe/docs/current/api/frappe.sessions.html
new file mode 100644
index 0000000000..84690315b5
--- /dev/null
+++ b/frappe/docs/current/api/frappe.sessions.html
@@ -0,0 +1,409 @@
+
+
+
+
+
+
+
+
+
Class Session
+
+
+
+
+
+
+
+
+
+
+ __init__
+ (self, user, resume=False, full_name=None, user_type=None)
+
+
+
+
+
+
+
+
+
+
+
+ delete_session
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ get_expiry_in_seconds
+ (self, expiry)
+
+
+
+
+
+
+
+
+
+
+
+ get_session_data
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ get_session_data_from_cache
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ get_session_data_from_db
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ get_session_record
+ (self)
+
+
get session record, or return the standard Guest Record
+
+
+
+
+
+
+
+
+
+
+ insert_session_record
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ resume
+ (self)
+
+
non-login request: load a session
+
+
+
+
+
+
+
+
+
+
+ start
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ start_as_guest
+ (self)
+
+
all guests share the same 'Guest' session
+
+
+
+
+
+
+
+
+
+
+ update
+ (self, force=False)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.sessions.clear
+
+
+
+
+ frappe.sessions.clear
+ (user=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.sessions.clear_all_sessions
+ ()
+
+
This effectively logs out all users
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.sessions.clear_cache
+ (user=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.sessions.clear_expired_sessions
+ ()
+
+
This function is meant to be called from scheduler
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.sessions.clear_global_cache
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.sessions.clear_sessions
+ (user=None, keep_current=False)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.sessions.delete_session
+ (sid=None, user=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.sessions.generate_csrf_token
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.sessions.get
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.sessions.get_csrf_token
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.sessions.get_expiry_period
+ (device=desktop)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.sessions.get_geo_from_ip
+ (ip_addr)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.sessions.get_geo_ip_country
+ (ip_addr)
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/frappe.setup_logging.html b/frappe/docs/current/api/frappe.setup_logging.html
new file mode 100644
index 0000000000..9e69171e9b
--- /dev/null
+++ b/frappe/docs/current/api/frappe.setup_logging.html
@@ -0,0 +1,63 @@
+
+
+
+
+
+
+
+
+
Class ContextFilter
+
+
Inherits from logging.Filter
+
+
This is a filter which injects request information (if available) into the log.
+
+
+
+
+
+
+
+
+
+ filter
+ (self, record)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.setup_logging.setup_logging
+ ()
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/frappe.share.html b/frappe/docs/current/api/frappe.share.html
new file mode 100644
index 0000000000..12702cf642
--- /dev/null
+++ b/frappe/docs/current/api/frappe.share.html
@@ -0,0 +1,160 @@
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.share.add
+
+
+
+
+ frappe.share.add
+ (doctype, name, user=None, read=1, write=0, share=0, everyone=0, flags=None)
+
+
Share the given document with a user.
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.share.check_share_permission
+ (doctype, name)
+
+
Check if the user can share with other users
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.share.get_share_name
+ (doctype, name, user, everyone)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.share.get_shared
+ (doctype, user=None, rights=None)
+
+
Get list of shared document names for given user and DocType.
+
+
Parameters:
+
+
+doctype - DocType of which shared names are queried.
+user - User for which shared names are queried.
+rights - List of rights for which the document is shared. List of read, write, share
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.share.get_shared_doctypes
+ (user=None)
+
+
Return list of doctypes in which documents are shared for the given user.
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.share.get_users
+
+
+
+
+ frappe.share.get_users
+ (doctype, name, fields=*)
+
+
Get list of users with which this document is shared
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.share.remove
+ (doctype, name, user, flags=None)
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.share.set_permission
+
+
+
+
+ frappe.share.set_permission
+ (doctype, name, user, permission_to, value=1, everyone=0)
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/frappe.tasks.html b/frappe/docs/current/api/frappe.tasks.html
new file mode 100644
index 0000000000..2432891b27
--- /dev/null
+++ b/frappe/docs/current/api/frappe.tasks.html
@@ -0,0 +1,98 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.tasks.get_active_queues
+ (app, worker)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.tasks.get_required_queues
+ (app, prefix=)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.tasks.get_workers
+ (app)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.tasks.is_site_in_maintenance_mode
+ (queue, prefix)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.tasks.sync_worker
+ (app, worker, prefix=)
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/frappe.test_runner.html b/frappe/docs/current/api/frappe.test_runner.html
new file mode 100644
index 0000000000..2836122651
--- /dev/null
+++ b/frappe/docs/current/api/frappe.test_runner.html
@@ -0,0 +1,226 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.test_runner._add_test
+ (path, filename, verbose, test_suite=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.test_runner._run_unittest
+ (module, verbose=False, tests=())
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.test_runner.get_dependencies
+ (doctype)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.test_runner.get_modules
+ (doctype)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.test_runner.main
+ (app=None, module=None, doctype=None, verbose=False, tests=(), force=False)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.test_runner.make_test_objects
+ (doctype, test_records, verbose=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.test_runner.make_test_records
+ (doctype, verbose=0, force=False)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.test_runner.make_test_records_for_doctype
+ (doctype, verbose=0, force=False)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.test_runner.print_mandatory_fields
+ (doctype)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.test_runner.run_all_tests
+ (app=None, verbose=False)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.test_runner.run_tests_for_doctype
+ (doctype, verbose=False, tests=(), force=False)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.test_runner.run_tests_for_module
+ (module, verbose=False, tests=())
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.test_runner.set_test_email_config
+ ()
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/frappe.translate.html b/frappe/docs/current/api/frappe.translate.html
new file mode 100644
index 0000000000..47629519d5
--- /dev/null
+++ b/frappe/docs/current/api/frappe.translate.html
@@ -0,0 +1,696 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.translate._get_messages_from_page_or_report
+ (doctype, name, module=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.translate.add_lang_dict
+ (code)
+
+
Extracts messages and returns Javascript code snippet to be appened at the end
+of the given script
+
+
Parameters:
+
+
+code - Javascript code snippet to which translations needs to be appended.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.translate.clear_cache
+ ()
+
+
Clear all translation assets from :meth:frappe.cache
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.translate.deduplicate_messages
+ (messages)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.translate.extract_messages_from_code
+ (code, is_py=False)
+
+
Extracts translatable srings from a code file
+
+
Parameters:
+
+
+code - code from which translatable files are to be extracted
+is_py - include messages in triple quotes e.g. _('''message''')
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.translate.get_all_languages
+ ()
+
+
Returns all language codes ar, ch etc
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.translate.get_all_messages_from_js_files
+ (app_name=None)
+
+
Extracts all translatable strings from app .js files
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.translate.get_bench_dir
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.translate.get_dict
+ (fortype, name=None)
+
+
Returns translation dict for a type of object.
+
+
Parameters:
+
+
+fortype - must be one of doctype, page, report, include, jsfile, boot
+name - name of the document for which assets are to be returned.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.translate.get_dict_from_hooks
+ (fortype, name)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.translate.get_full_dict
+ (lang)
+
+
Load and return the entire translations dictionary for a language from :meth:frape.cache
+
+
Parameters:
+
+
+lang - Language Code, e.g. hi
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.translate.get_lang_dict
+ ()
+
+
Returns all languages in dict format, full name is the key e.g. {"english":"en"}
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.translate.get_lang_info
+ ()
+
+
Returns a listified version of apps/languages.txt
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.translate.get_lang_js
+ (fortype, name)
+
+
Returns code snippet to be appended at the end of a JS script.
+
+
Parameters:
+
+
+fortype - Type of object, e.g. DocType
+name - Document name
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.translate.get_language_from_code
+ (lang)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.translate.get_messages_for_app
+ (app)
+
+
Returns all messages (list) for a specified app
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.translate.get_messages_from_doctype
+ (name)
+
+
Extract all translatable messages for a doctype. Includes labels, Python code,
+Javascript code, html templates
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.translate.get_messages_from_file
+ (path)
+
+
Returns a list of transatable strings from a code file
+
+
Parameters:
+
+
+path - path of the code file
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.translate.get_messages_from_include_files
+ (app_name=None)
+
+
Returns messages from js files included at time of boot like desk.min.js for desk and web
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.translate.get_messages_from_page
+ (name)
+
+
Returns all translatable strings from a :class:frappe.core.doctype.Page
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.translate.get_messages_from_report
+ (name)
+
+
Returns all translatable strings from a :class:frappe.core.doctype.Report
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.translate.get_server_messages
+ (app)
+
+
Extracts all translatable strings (tagged with :func:frappe._) from Python modules inside an app
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.translate.get_untranslated
+ (lang, untranslated_file, get_all=False)
+
+
Returns all untranslated strings for a language and writes in a file
+
+
Parameters:
+
+
+lang - Language code.
+untranslated_file - Output file path.
+get_all - Return all strings, translated or not.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.translate.get_user_lang
+ (user=None)
+
+
Set frappe.local.lang from user preferences on session beginning or resumption
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.translate.guess_language
+ (lang_list=None)
+
+
Set frappe.local.lang from HTTP headers at beginning of request
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.translate.is_translatable
+ (m)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.translate.load_lang
+ (lang, apps=None)
+
+
Combine all translations from .csv files in all apps
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.translate.make_dict_from_messages
+ (messages, full_dict=None)
+
+
Returns translated messages as a dict in Language specified in frappe.local.lang
+
+
Parameters:
+
+
+messages - List of untranslated messages
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.translate.pos_to_line_no
+ (messages, code)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.translate.read_csv_file
+ (path)
+
+
Read CSV file and return as list of list
+
+
Parameters:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.translate.rebuild_all_translation_files
+ ()
+
+
Rebuild all translation files: [app]/translations/[lang].csv.
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.translate.rename_language
+ (old_name, new_name)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.translate.send_translations
+ (translation_dict)
+
+
Append translated dict in frappe.local.response
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.translate.set_default_language
+ (language)
+
+
Set Global default language
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.translate.update_translations
+ (lang, untranslated_file, translated_file)
+
+
Update translations from a source and target file for a given language.
+
+
Parameters:
+
+
+lang - Language code (e.g. en).
+untranslated_file - File path with the messages in English.
+translated_file - File path with messages in language to be updated.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.translate.write_csv_file
+ (path, app_messages, lang_dict)
+
+
Write translation CSV file.
+
+
Parameters:
+
+
+path - File path, usually [app]/translations.
+app_messages - Translatable strings for this app.
+lang_dict - Full translated dict.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.translate.write_translations_file
+ (app, lang, full_dict=None, app_messages=None)
+
+
Write a translation file for a given language.
+
+
Parameters:
+
+
+app - app for which translations are to be written.
+lang - Language code.
+full_dict - Full translated langauge dict (optional).
+app_messages - Source strings (optional).
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/geo/frappe.geo.country_info.html b/frappe/docs/current/api/geo/frappe.geo.country_info.html
new file mode 100644
index 0000000000..79f39c8f85
--- /dev/null
+++ b/frappe/docs/current/api/geo/frappe.geo.country_info.html
@@ -0,0 +1,100 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.geo.country_info.get_all
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.geo.country_info.get_country_info
+ (country=None)
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.geo.country_info.get_country_timezone_info
+
+
+
+
+ frappe.geo.country_info.get_country_timezone_info
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.geo.country_info.get_translated_dict
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.geo.country_info.update
+ ()
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/geo/frappe.geo.html b/frappe/docs/current/api/geo/frappe.geo.html
new file mode 100644
index 0000000000..b1d6615dd4
--- /dev/null
+++ b/frappe/docs/current/api/geo/frappe.geo.html
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/geo/index.html b/frappe/docs/current/api/geo/index.html
new file mode 100644
index 0000000000..b12014263f
--- /dev/null
+++ b/frappe/docs/current/api/geo/index.html
@@ -0,0 +1,19 @@
+
+
+
+
+
+
Package Contents
+
+{index}
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/geo/index.txt b/frappe/docs/current/api/geo/index.txt
new file mode 100644
index 0000000000..78635c807a
--- /dev/null
+++ b/frappe/docs/current/api/geo/index.txt
@@ -0,0 +1,2 @@
+frappe.geo.country_info
+frappe.geo
\ No newline at end of file
diff --git a/frappe/docs/current/api/index.html b/frappe/docs/current/api/index.html
new file mode 100644
index 0000000000..6264153df7
--- /dev/null
+++ b/frappe/docs/current/api/index.html
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
Contents
+
+
+
+{index}
\ No newline at end of file
diff --git a/frappe/docs/current/api/index.txt b/frappe/docs/current/api/index.txt
new file mode 100644
index 0000000000..9384b73ebe
--- /dev/null
+++ b/frappe/docs/current/api/index.txt
@@ -0,0 +1,27 @@
+frappe.__init__
+frappe.__version__
+frappe.api
+frappe.app
+frappe.async
+frappe.auth
+frappe.boot
+frappe.build
+frappe.celery_app
+frappe.client
+frappe.commands
+frappe.database
+frappe.defaults
+frappe.exceptions
+frappe.frappeclient
+frappe.handler
+frappe.hooks
+frappe.installer
+frappe.middlewares
+frappe.permissions
+frappe.pythonrc
+frappe.sessions
+frappe.setup_logging
+frappe.share
+frappe.tasks
+frappe.test_runner
+frappe.translate
\ No newline at end of file
diff --git a/frappe/docs/current/api/integrations/frappe.integrations.html b/frappe/docs/current/api/integrations/frappe.integrations.html
new file mode 100644
index 0000000000..e9fc3a23a4
--- /dev/null
+++ b/frappe/docs/current/api/integrations/frappe.integrations.html
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/integrations/index.html b/frappe/docs/current/api/integrations/index.html
new file mode 100644
index 0000000000..9fd8a01433
--- /dev/null
+++ b/frappe/docs/current/api/integrations/index.html
@@ -0,0 +1,19 @@
+
+
+
+
+
+
Package Contents
+
+{index}
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/integrations/index.txt b/frappe/docs/current/api/integrations/index.txt
new file mode 100644
index 0000000000..1dce3c404d
--- /dev/null
+++ b/frappe/docs/current/api/integrations/index.txt
@@ -0,0 +1 @@
+frappe.integrations
\ No newline at end of file
diff --git a/frappe/docs/current/api/model/frappe.model.base_document.html b/frappe/docs/current/api/model/frappe.model.base_document.html
new file mode 100644
index 0000000000..18978a780e
--- /dev/null
+++ b/frappe/docs/current/api/model/frappe.model.base_document.html
@@ -0,0 +1,643 @@
+
+
+
+
+
+
+
+
+
Class BaseDocument
+
+
Inherits from __builtin__.object
+
+
+
+
+
+
+
+
+
+
+ __init__
+ (self, d)
+
+
+
+
+
+
+
+
+
+
+
+ _extract_images_from_text_editor
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ _fix_numeric_types
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ _get_missing_mandatory_fields
+ (self)
+
+
Get mandatory fields that do not have any values
+
+
+
+
+
+
+
+
+
+
+ _init_child
+ (self, value, key)
+
+
+
+
+
+
+
+
+
+
+
+ _validate_constants
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ _validate_length
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ _validate_selects
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ _validate_update_after_submit
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ append
+ (self, key, value=None)
+
+
+
+
+
+
+
+
+
+
+
+ as_dict
+ (self, no_nulls=False, no_default_fields=False)
+
+
+
+
+
+
+
+
+
+
+
+ as_json
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ cast
+ (self, val, df)
+
+
+
+
+
+
+
+
+
+
+
+ db_insert
+ (self)
+
+
INSERT the document (with valid columns) in the database.
+
+
+
+
+
+
+
+
+
+
+ db_set
+ (self, fieldname, value, update_modified=True)
+
+
+
+
+
+
+
+
+
+
+
+ db_update
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ delete_key
+ (self, key)
+
+
+
+
+
+
+
+
+
+
+
+ extend
+ (self, key, value)
+
+
+
+
+
+
+
+
+
+
+
+ get
+ (self, key=None, filters=None, limit=None, default=None)
+
+
+
+
+
+
+
+
+
+
+
+ get_db_value
+ (self, key)
+
+
+
+
+
+
+
+
+
+
+
+ get_formatted
+ (self, fieldname, doc=None, currency=None, absolute_value=False)
+
+
+
+
+
+
+
+
+
+
+
+ get_invalid_links
+ (self, is_submittable=False)
+
+
+
+
+
+
+
+
+
+
+
+ get_parentfield_of_doctype
+ (self, doctype)
+
+
+
+
+
+
+
+
+
+
+
+ get_table_field_doctype
+ (self, fieldname)
+
+
+
+
+
+
+
+
+
+
+
+ get_valid_columns
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ get_valid_dict
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ get_value
+ (self, fieldname)
+
+
+
+
+
+
+
+
+
+
+
+ getone
+ (self, key, filters=None)
+
+
+
+
+
+
+
+
+
+
+
+ in_format_data
+ (self, fieldname)
+
+
Returns True if shown via Print Format::format_data property.
+Called from within standard print format.
+
+
+
+
+
+
+
+
+
+
+ init_valid_columns
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ is_new
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ is_print_hide
+ (self, fieldname, df=None, for_print=True)
+
+
Returns true if fieldname is to be hidden for print.
+
+
Print Hide can be set via the Print Format Builder or in the controller as a list
+of hidden fields. Example
+
+
class MyDoc(Document):
+ def __setup__(self):
+ self.print_hide = ["field1", "field2"]
+
+
+
Parameters:
+
+
+fieldname - Fieldname to be checked if hidden.
+
+
+
+
+
+
+
+
+
+
+
+ precision
+ (self, fieldname, parentfield=None)
+
+
Returns float precision for a particular field (or get global default).
+
+
Parameters:
+
+
+fieldname - Fieldname for which precision is required.
+parentfield - If fieldname is in child table.
+
+
+
+
+
+
+
+
+
+
+
+ remove
+ (self, doc)
+
+
+
+
+
+
+
+
+
+
+
+ reset_values_if_no_permlevel_access
+ (self, has_access_to, high_permlevel_fields)
+
+
If the user does not have permissions at permlevel > 0, then reset the values to original / default
+
+
+
+
+
+
+
+
+
+
+ set
+ (self, key, value, as_value=False)
+
+
+
+
+
+
+
+
+
+
+
+ show_unique_validation_message
+ (self, e)
+
+
+
+
+
+
+
+
+
+
+
+ update
+ (self, d)
+
+
+
+
+
+
+
+
+
+
+
+ update_if_missing
+ (self, d)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.base_document._filter
+ (data, filters, limit=None)
+
+
pass filters as:
+{"key": "val", "key": ["!=", "val"],
+"key": ["in", "val"], "key": ["not in", "val"], "key": "^val",
+"key" : True (exists), "key": False (does not exist) }
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.base_document.get_controller
+ (doctype)
+
+
Returns the class object of the given DocType.
+For custom type, returns frappe.model.document.Document.
+
+
Parameters:
+
+
+doctype - DocType name as string.
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/model/frappe.model.create_new.html b/frappe/docs/current/api/model/frappe.model.create_new.html
new file mode 100644
index 0000000000..dcf614f7b9
--- /dev/null
+++ b/frappe/docs/current/api/model/frappe.model.create_new.html
@@ -0,0 +1,146 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.create_new.get_default_based_on_another_field
+ (df, user_permissions, parent_doc)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.create_new.get_new_doc
+ (doctype, parent_doc=None, parentfield=None, as_dict=False)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.create_new.get_static_default_value
+ (df, user_permissions)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.create_new.get_user_default_value
+ (df, defaults, user_permissions)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.create_new.make_new_doc
+ (doctype)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.create_new.set_dynamic_default_values
+ (doc, parent_doc, parentfield)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.create_new.set_user_and_static_default_values
+ (doc)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.create_new.user_permissions_exist
+ (df, user_permissions)
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/model/frappe.model.db_query.html b/frappe/docs/current/api/model/frappe.model.db_query.html
new file mode 100644
index 0000000000..25bc99f50f
--- /dev/null
+++ b/frappe/docs/current/api/model/frappe.model.db_query.html
@@ -0,0 +1,336 @@
+
+
+
+
+
+
+
+
+
Class DatabaseQuery
+
+
Inherits from __builtin__.object
+
+
+
+
+
+
+
+
+
+
+ __init__
+ (self, doctype)
+
+
+
+
+
+
+
+
+
+
+
+ add_limit
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ add_user_permissions
+ (self, user_permissions, user_permission_doctypes=None)
+
+
+
+
+
+
+
+
+
+
+
+ append_table
+ (self, table_name)
+
+
+
+
+
+
+
+
+
+
+
+ build_and_run
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ build_conditions
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ build_filter_conditions
+ (self, filters, conditions)
+
+
build conditions from user filters
+
+
+
+
+
+
+
+
+
+
+ build_match_conditions
+ (self, as_condition=True)
+
+
add match conditions if applicable
+
+
+
+
+
+
+
+
+
+
+ check_sort_by_table
+ (self, order_by)
+
+
+
+
+
+
+
+
+
+
+
+ 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)
+
+
+
+
+
+
+
+
+
+
+
+ extract_tables
+ (self)
+
+
extract tables from fields
+
+
+
+
+
+
+
+
+
+
+ get_filter
+ (self, f)
+
+
Returns a _dict like
+
+
{
+ "doctype": "DocType",
+ "fieldname": "fieldname",
+ "operator": "=",
+ "value": "value"
+}
+
+
+
+
+
+
+
+
+
+
+ get_permission_query_conditions
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ get_share_condition
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ make_filter_tuple
+ (self, key, value)
+
+
+
+
+
+
+
+
+
+
+
+ parse_args
+ (self)
+
+
Convert fields and filters from strings to list, dicts
+
+
+
+
+
+
+
+
+
+
+ prepare_args
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ prepare_filter_condition
+ (self, f)
+
+
Returns a filter condition in the format:
+
+
ifnull(tabDocType.fieldname, fallback) operator "value"
+
+
+
+
+
+
+
+
+
+
+ remove_user_tags
+ (self)
+
+
Removes optional columns like _user_tags, _comments etc. if not in table
+
+
+
+
+
+
+
+
+
+
+ run_custom_query
+ (self, query)
+
+
+
+
+
+
+
+
+
+
+
+ set_order_by
+ (self, args)
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/model/frappe.model.db_schema.html b/frappe/docs/current/api/model/frappe.model.db_schema.html
new file mode 100644
index 0000000000..95b441b3e3
--- /dev/null
+++ b/frappe/docs/current/api/model/frappe.model.db_schema.html
@@ -0,0 +1,597 @@
+
+
+
+
+
+
+
+
+
Class DbColumn
+
+
+
+
+
+
+
+
+
+
+ __init__
+ (self, table, fieldname, fieldtype, length, default, set_index, options, unique, precision)
+
+
+
+
+
+
+
+
+
+
+
+ build_for_alter_table
+ (self, current_def)
+
+
+
+
+
+
+
+
+
+
+
+ default_changed
+ (self, current_def)
+
+
+
+
+
+
+
+
+
+
+
+ default_changed_for_decimal
+ (self, current_def)
+
+
+
+
+
+
+
+
+
+
+
+ get_definition
+ (self, with_default=1)
+
+
+
+
+
+
+
+
+
+
+
+
+
Class DbManager
+
+
Basically, a wrapper for oft-used mysql commands. like show tables,databases, variables etc...
+
+
TODO:
+
+
0. Simplify / create settings for the restore database source folder
+0a. Merge restore database and extract_sql(from frappe_server_tools).
+1. Setter and getter for different mysql variables.
+2. Setter and getter for mysql variables at global level??
+
+
+
+
+
+
+
+
+
+
+ __init__
+ (self, db)
+
+
Pass root_conn here for access to all databases.
+
+
+
+
+
+
+
+
+
+
+ create_database
+ (self, target)
+
+
+
+
+
+
+
+
+
+
+
+ create_user
+ (self, user, password, host)
+
+
+
+
+
+
+
+
+
+
+
+ delete_user
+ (self, target, host)
+
+
+
+
+
+
+
+
+
+
+
+ drop_database
+ (self, target)
+
+
+
+
+
+
+
+
+
+
+
+ drop_table
+ (self, table_name)
+
+
+
+
+
+
+
+
+
+
+
+ flush_privileges
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ get_database_list
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ get_table_schema
+ (self, table)
+
+
Just returns the output of Desc tables.
+
+
+
+
+
+
+
+
+
+
+ get_tables_list
+ (self, target=None)
+
+
+
+
+
+
+
+
+
+
+
+ get_variables
+ (self, regex)
+
+
Get variables that match the passed pattern regex
+
+
+
+
+
+
+
+
+
+
+ grant_all_privileges
+ (self, target, user, host)
+
+
+
+
+
+
+
+
+
+
+
+ grant_select_privilges
+ (self, db, table, user, host)
+
+
+
+
+
+
+
+
+
+
+
+ restore_database
+ (self, target, source, user, password)
+
+
+
+
+
+
+
+
+
+
+
+
+
Class DbTable
+
+
+
+
+
+
+
+
+
+
+ __init__
+ (self, doctype, prefix=tab)
+
+
+
+
+
+
+
+
+
+
+
+ alter
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ create
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ drop_foreign_keys
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ get_column_definitions
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ get_columns_from_db
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ get_columns_from_docfields
+ (self)
+
+
get columns from docfields and custom fields
+
+
+
+
+
+
+
+
+
+
+ get_foreign_keys
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ get_index_definitions
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ is_new
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ sync
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ validate
+ (self)
+
+
Check if change in varchar length isn't truncating the columns
+
+
+
+
+
+
+
+
+
+
+
+
Class InvalidColumnName
+
+
Inherits from frappe.exceptions.ValidationError
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.db_schema.add_column
+ (doctype, column_name, fieldtype, precision=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.db_schema.get_definition
+ (fieldtype, precision=None, length=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.db_schema.remove_all_foreign_keys
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.db_schema.updatedb
+ (dt)
+
+
Syncs a DocType to the table
+ * creates if required
+ * updates columns
+ * updates indices
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.db_schema.validate_column_name
+ (n)
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/model/frappe.model.delete_doc.html b/frappe/docs/current/api/model/frappe.model.delete_doc.html
new file mode 100644
index 0000000000..3b3028d9ce
--- /dev/null
+++ b/frappe/docs/current/api/model/frappe.model.delete_doc.html
@@ -0,0 +1,194 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.delete_doc.check_if_doc_is_dynamically_linked
+ (doc, method=Delete)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.delete_doc.check_if_doc_is_linked
+ (doc, method=Delete)
+
+
Raises excption if the given doc(dt, dn) is linked in another record.
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.delete_doc.check_permission_and_not_submitted
+ (doc)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.delete_doc.delete_doc
+ (doctype=None, name=None, force=0, ignore_doctypes=None, for_reload=False, ignore_permissions=False, flags=None, ignore_on_trash=False)
+
+
Deletes a doc(dt, dn) and validates if it is not submitted and not linked in a live record
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.delete_doc.delete_from_table
+ (doctype, name, ignore_doctypes, doc)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.delete_doc.delete_linked_comments
+ (doc)
+
+
Delete comments from the document
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.delete_doc.delete_linked_communications
+ (doc)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.delete_doc.delete_linked_todos
+ (doc)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.delete_doc.delete_shared
+ (doc)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.delete_doc.insert_feed
+ (doc)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.delete_doc.update_naming_series
+ (doc)
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/model/frappe.model.docfield.html b/frappe/docs/current/api/model/frappe.model.docfield.html
new file mode 100644
index 0000000000..fa5a04b93c
--- /dev/null
+++ b/frappe/docs/current/api/model/frappe.model.docfield.html
@@ -0,0 +1,98 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.docfield.get_change_column_query
+ (f, new)
+
+
generate change fieldname query
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.docfield.rename
+ (doctype, fieldname, newname)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.docfield.update_parent_field
+ (f, new)
+
+
update 'parentfield' in tables
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.docfield.update_single
+ (f, new)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.docfield.update_table
+ (f, new)
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/model/frappe.model.document.html b/frappe/docs/current/api/model/frappe.model.document.html
new file mode 100644
index 0000000000..970a493bd6
--- /dev/null
+++ b/frappe/docs/current/api/model/frappe.model.document.html
@@ -0,0 +1,788 @@
+
+
+
+
+
+
+
+
+
Class Document
+
+
Inherits from frappe.model.base_document.BaseDocument
+
+
All controllers inherit from Document.
+
+
+
+
+
+
+
+
+
+ __init__
+ (self, arg1, arg2=None)
+
+
Constructor.
+
+
Parameters:
+
+
+arg1 - DocType name as string or document dict
+arg2 - Document name, if arg1 is DocType name.
+
+
+
If DocType name and document name are passed, the object will load
+all values (including child documents) from the database.
+
+
+
+
+
+
+
+
+
+
+ _set_defaults
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ _validate
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ _validate_links
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ _validate_mandatory
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ add_comment
+ (self, comment_type, text=None, comment_by=None)
+
+
Add a comment to this document.
+
+
Parameters:
+
+
+comment_type - e.g. Comment. See Comment for more info.
+
+
+
+
+
+
+
+
+
+
+
+ cancel
+ (self)
+
+
Cancel the document. Sets docstatus = 2, then saves.
+
+
+
+
+
+
+
+
+
+
+ check_docstatus_transition
+ (self, docstatus)
+
+
Ensures valid docstatus transition.
+Valid transitions are (number in brackets is docstatus):
+
+
+Save (0) > Save (0)
+Save (0) > Submit (1)
+Submit (1) > Submit (1)
+Submit (1) > Cancel (2)
+
+
+
+
+
+
+
+
+
+
+
+ check_if_latest
+ (self)
+
+
Checks if modified timestamp provided by document being updated is same as the
+modified timestamp in the database. If there is a different, the document has been
+updated in the database after the current copy was read. Will throw an error if
+timestamps don't match.
+
+
Will also validate document transitions (Save > Submit > Cancel) calling
+self.check_docstatus_transition.
+
+
+
+
+
+
+
+
+
+
+ check_no_back_links_exist
+ (self)
+
+
Check if document links to any active document before Cancel.
+
+
+
+
+
+
+
+
+
+
+ check_permission
+ (self, permtype, permlabel=None)
+
+
Raise frappe.PermissionError if not permitted
+
+
+
+
+
+
+
+
+
+
+ clear_cache
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ clear_linked_with_cache
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ delete
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ get_all_children
+ (self, parenttype=None)
+
+
Returns all children documents from Table type field in a list.
+
+
+
+
+
+
+
+
+
+
+ get_latest
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ get_permlevel_access
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ get_signature
+ (self)
+
+
Returns signature (hash) for private URL.
+
+
+
+
+
+
+
+
+
+
+ get_starred_by
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ get_url
+ (self)
+
+
Returns Desk URL for this document. /desk#Form/{doctype}/{name}
+
+
+
+
+
+
+
+
+
+
+ has_permission
+ (self, permtype=read, verbose=False)
+
+
Call frappe.has_permission if self.flags.ignore_permissions
+is not set.
+
+
Parameters:
+
+
+permtype - one of read, write, submit, cancel, delete
+
+
+
+
+
+
+
+
+
+
+
+ has_website_permission
+ (self, permtype=read, verbose=False)
+
+
Call frappe.has_website_permission if self.flags.ignore_permissions
+is not set.
+
+
Parameters:
+
+
+permtype - one of read, write, submit, cancel, delete
+
+
+
+
+
+
+
+
+
+
+
+ insert
+ (self, ignore_permissions=None)
+
+
Insert the document in the database (as a new document).
+This will check for user permissions and execute before_insert,
+validate, on_update, after_insert methods if they are written.
+
+
Parameters:
+
+
+ignore_permissions - Do not check permissions if True.
+
+
+
+
+
+
+
+
+
+
+
+ is_whitelisted
+ (self, method)
+
+
+
+
+
+
+
+
+
+
+
+ load_from_db
+ (self)
+
+
Load document and children from database and create properties
+from fields
+
+
+
+
+
+
+
+
+
+
+ notify_update
+ (self)
+
+
Publish realtime that the current document is modified
+
+
+
+
+
+
+
+
+
+
+ raise_no_permission_to
+ (self, perm_type)
+
+
Raise frappe.PermissionError.
+
+
+
+
+
+
+
+
+
+
+ reload
+ (self)
+
+
Reload document from database
+
+
+
+
+
+
+
+
+
+
+ round_floats_in
+ (self, doc, fieldnames=None)
+
+
Round floats for all Currency, Float, Percent fields for the given doc.
+
+
Parameters:
+
+
+doc - Document whose numeric properties are to be rounded.
+fieldnames - [Optional] List of fields to be rounded.
+
+
+
+
+
+
+
+
+
+
+
+ run_before_save_methods
+ (self)
+
+
Run standard methods before INSERT or UPDATE. Standard Methods are:
+
+
+validate, before_save for Save .
+validate, before_submit for Submit .
+before_cancel for Cancel
+before_update_after_submit for Update after Submit
+
+
+
Will also update title_field if set
+
+
+
+
+
+
+
+
+
+
+ run_method
+ (self, method)
+
+
run standard triggers, plus those in hooks
+
+
+
+
+
+
+
+
+
+
+ run_post_save_methods
+ (self)
+
+
Run standard methods after INSERT or UPDATE. Standard Methods are:
+
+
+on_update for Save .
+on_update, on_submit for Submit .
+on_cancel for Cancel
+update_after_submit for Update after Submit
+
+
+
+
+
+
+
+
+
+
+
+ save
+ (self, ignore_permissions=None)
+
+
Save the current document in the database in the DocType 's table or
+tabSingles (for single types).
+
+
This will check for user permissions and execute
+validate before updating, on_update after updating triggers.
+
+
Parameters:
+
+
+ignore_permissions - Do not check permissions if True.
+
+
+
+
+
+
+
+
+
+
+
+ set_docstatus_user_and_timestamp
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ set_new_name
+ (self)
+
+
Calls frappe.naming.se_new_name for parent and child docs.
+
+
+
+
+
+
+
+
+
+
+ set_onload
+ (self, key, value)
+
+
+
+
+
+
+
+
+
+
+
+ set_parent_in_children
+ (self)
+
+
Updates parent and parenttype property in all children.
+
+
+
+
+
+
+
+
+
+
+ set_title_field
+ (self)
+
+
Set title field based on template
+
+
+
+
+
+
+
+
+
+
+ submit
+ (self)
+
+
Submit the document. Sets docstatus = 1, then saves.
+
+
+
+
+
+
+
+
+
+
+ update_children
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ update_single
+ (self, d)
+
+
Updates values for Single type Document in tabSingles.
+
+
+
+
+
+
+
+
+
+
+ validate_higher_perm_levels
+ (self)
+
+
If the user does not have permissions at permlevel > 0, then reset the values to original / default
+
+
+
+
+
+
+
+
+
+
+ validate_table_has_rows
+ (self, parentfield, raise_exception=None)
+
+
Raise exception if Table field is empty.
+
+
+
+
+
+
+
+
+
+
+ validate_update_after_submit
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ validate_value
+ (self, fieldname, condition, val2, doc=None, raise_exception=None)
+
+
Check that value of fieldname should be 'condition' val2
+else throw Exception.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.document.get_doc
+ (arg1, arg2=None)
+
+
returns a frappe.model.Document object.
+
+
Parameters:
+
+
+arg1 - Document dict or DocType name.
+arg2 - [optional] document name.
+
+
+
There are two ways to call get_doc
+
+
# will fetch the latest user object (with child table) from the database
+user = get_doc("User", "test@example.com")
+
+# create a new object
+user = get_doc({
+ "doctype":"User"
+ "email_id": "test@example.com",
+ "user_roles: [
+ {"role": "System Manager"}
+ ]
+})
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/model/frappe.model.html b/frappe/docs/current/api/model/frappe.model.html
new file mode 100644
index 0000000000..c5376eab88
--- /dev/null
+++ b/frappe/docs/current/api/model/frappe.model.html
@@ -0,0 +1,87 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.copytables
+ (srctype, src, srcfield, tartype, tar, tarfield, srcfields, tarfields=[])
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.db_exists
+ (dt, dn)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.delete_fields
+ (args_dict, delete=0)
+
+
Delete a field.
+* Deletes record from tabDocField
+* If not single doctype: Drops column from table
+* If single, deletes record from tabSingles
+
+
args_dict = { dt: [field names] }
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.rename
+ (doctype, old, new, debug=False)
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/model/frappe.model.mapper.html b/frappe/docs/current/api/model/frappe.model.mapper.html
new file mode 100644
index 0000000000..cbf7050179
--- /dev/null
+++ b/frappe/docs/current/api/model/frappe.model.mapper.html
@@ -0,0 +1,98 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.mapper.get_mapped_doc
+ (from_doctype, from_docname, table_maps, target_doc=None, postprocess=None, ignore_permissions=False)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.mapper.map_child_doc
+ (source_d, target_parent, table_map, source_parent=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.mapper.map_doc
+ (source_doc, target_doc, table_map, source_parent=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.mapper.map_fetch_fields
+ (target_doc, df, no_copy_fields)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.mapper.map_fields
+ (source_doc, target_doc, table_map, source_parent)
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/model/frappe.model.meta.html b/frappe/docs/current/api/model/frappe.model.meta.html
new file mode 100644
index 0000000000..f2a1911995
--- /dev/null
+++ b/frappe/docs/current/api/model/frappe.model.meta.html
@@ -0,0 +1,489 @@
+
+
+
+
+
+
+
+
+
Class Meta
+
+
Inherits from frappe.model.document.Document
+
+
+
+
+
+
+
+
+
+
+ __init__
+ (self, doctype)
+
+
+
+
+
+
+
+
+
+
+
+ add_custom_fields
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ apply_property_setters
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ get_dynamic_link_fields
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ get_field
+ (self, fieldname)
+
+
+
+
+
+
+
+
+
+
+
+ get_fields_to_check_permissions
+ (self, user_permission_doctypes)
+
+
+
+
+
+
+
+
+
+
+
+ get_high_permlevel_fields
+ (self)
+
+
Build list of fields with high perm level and all the higher perm levels defined.
+
+
+
+
+
+
+
+
+
+
+ get_label
+ (self, fieldname)
+
+
+
+
+
+
+
+
+
+
+
+ get_link_fields
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ get_list_fields
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ get_options
+ (self, fieldname)
+
+
+
+
+
+
+
+
+
+
+
+ get_search_fields
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ get_select_fields
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ get_table_field_doctype
+ (self, fieldname)
+
+
+
+
+
+
+
+
+
+
+
+ get_table_fields
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ get_title_field
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ get_valid_columns
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ load_from_db
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ process
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ sort_fields
+ (self)
+
+
sort on basis of previous_field
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.meta.clear_cache
+ (doctype=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.meta.get_default_df
+ (fieldname)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.meta.get_field_currency
+ (df, doc=None)
+
+
get currency based on DocField options and fieldvalue in doc
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.meta.get_field_precision
+ (df, doc=None, currency=None)
+
+
get precision based on DocField options and fieldvalue in doc
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.meta.get_meta
+ (doctype, cached=True)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.meta.get_parent_dt
+ (dt)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.meta.get_table_columns
+ (doctype)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.meta.is_single
+ (doctype)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.meta.load_doctype_from_file
+ (doctype)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.meta.set_fieldname
+ (field_id, fieldname)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.meta.trim_tables
+ ()
+
+
Use this to remove columns that don't exist in meta
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/model/frappe.model.naming.html b/frappe/docs/current/api/model/frappe.model.naming.html
new file mode 100644
index 0000000000..b0f83b811f
--- /dev/null
+++ b/frappe/docs/current/api/model/frappe.model.naming.html
@@ -0,0 +1,209 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.naming._set_amended_name
+ (doc)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.naming.append_number_if_name_exists
+ (doc)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.naming.de_duplicate
+ (doctype, name)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.naming.get_default_naming_series
+ (doctype)
+
+
get default value for naming_series property
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.naming.getseries
+ (key, digits, doctype=)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.naming.make_autoname
+ (key, doctype=)
+
+
Creates an autoname from the given key:
+
+
Autoname rules:
+
+
* The key is separated by '.'
+ * '####' represents a series. The string before this part becomes the prefix:
+ Example: ABC.#### creates a series ABC0001, ABC0002 etc
+ * 'MM' represents the current month
+ * 'YY' and 'YYYY' represent the current year
+
+
+
Example:
+
+
* DE/./.YY./.MM./.##### will create a series like
+ DE/09/01/0001 where 09 is the year, 01 is the month and 0001 is the series
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.naming.revert_series_if_last
+ (key, name)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.naming.set_name_by_naming_series
+ (doc)
+
+
Sets name by the naming_series property
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.naming.set_new_name
+ (doc)
+
+
Sets the `name`` property for the document based on various rules.
+
+
+If amened doc, set suffix.
+If autoname method is declared, then call it.
+If autoname property is set in the DocType (meta), then build it using the autoname property.
+If name is already defined, use that name
+If no rule defined, use hash.
+
+
+
Note:
+
+
Parameters:
+
+
+doc - Document to be named.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.naming.validate_name
+ (doctype, name, case=None, merge=False)
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/model/frappe.model.rename_doc.html b/frappe/docs/current/api/model/frappe.model.rename_doc.html
new file mode 100644
index 0000000000..5839ba0432
--- /dev/null
+++ b/frappe/docs/current/api/model/frappe.model.rename_doc.html
@@ -0,0 +1,285 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.rename_doc.bulk_rename
+ (doctype, rows=None, via_console=False)
+
+
Bulk rename documents
+
+
Parameters:
+
+
+doctype - DocType to be renamed
+rows - list of documents as ((oldname, newname), ..)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.rename_doc.get_link_fields
+ (doctype)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.rename_doc.get_select_fields
+ (old, new)
+
+
get select type fields where doctype's name is hardcoded as
+new line separated list
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.model.rename_doc.rename_doc
+
+
+
+
+ frappe.model.rename_doc.rename_doc
+ (doctype, old, new, force=False, merge=False, ignore_permissions=False)
+
+
Renames a doc(dt, old) to doc(dt, new) and
+updates all linked fields of type "Link"
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.rename_doc.rename_doctype
+ (doctype, old, new, force=False)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.rename_doc.rename_dynamic_links
+ (doctype, old, new)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.rename_doc.rename_parent_and_child
+ (doctype, old, new, meta)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.rename_doc.rename_versions
+ (doctype, old, new)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.rename_doc.update_attachments
+ (doctype, old, new)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.rename_doc.update_child_docs
+ (old, new, meta)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.rename_doc.update_comments
+ (doctype, old, new, force=False)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.rename_doc.update_link_field_values
+ (link_fields, old, new, doctype)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.rename_doc.update_options_for_fieldtype
+ (fieldtype, old, new)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.rename_doc.update_parenttype_values
+ (old, new)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.rename_doc.update_select_field_values
+ (old, new)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.rename_doc.validate_rename
+ (doctype, new, meta, merge, force, ignore_permissions)
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/model/frappe.model.sync.html b/frappe/docs/current/api/model/frappe.model.sync.html
new file mode 100644
index 0000000000..f48a76638c
--- /dev/null
+++ b/frappe/docs/current/api/model/frappe.model.sync.html
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.sync.get_doc_files
+ (files, start_path, force=0, sync_everything=False, verbose=False)
+
+
walk and sync all doctypes and pages
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.sync.sync_all
+ (force=0, verbose=False)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.sync.sync_for
+ (app_name, force=0, sync_everything=False, verbose=False)
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/model/frappe.model.workflow.html b/frappe/docs/current/api/model/frappe.model.workflow.html
new file mode 100644
index 0000000000..d6edf08f22
--- /dev/null
+++ b/frappe/docs/current/api/model/frappe.model.workflow.html
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.workflow.get_default_state
+ (doctype)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.workflow.get_state_fieldname
+ (doctype)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.workflow.get_workflow_name
+ (doctype)
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/model/index.html b/frappe/docs/current/api/model/index.html
new file mode 100644
index 0000000000..52266ed572
--- /dev/null
+++ b/frappe/docs/current/api/model/index.html
@@ -0,0 +1,19 @@
+
+
+
+
+
+
Package Contents
+
+{index}
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/model/index.txt b/frappe/docs/current/api/model/index.txt
new file mode 100644
index 0000000000..7dc8257c25
--- /dev/null
+++ b/frappe/docs/current/api/model/index.txt
@@ -0,0 +1,14 @@
+frappe.model.base_document
+frappe.model.create_new
+frappe.model.db_query
+frappe.model.db_schema
+frappe.model.delete_doc
+frappe.model.docfield
+frappe.model.document
+frappe.model
+frappe.model.mapper
+frappe.model.meta
+frappe.model.naming
+frappe.model.rename_doc
+frappe.model.sync
+frappe.model.workflow
\ No newline at end of file
diff --git a/frappe/docs/current/api/model/utils/frappe.model.utils.html b/frappe/docs/current/api/model/utils/frappe.model.utils.html
new file mode 100644
index 0000000000..6fa42fb528
--- /dev/null
+++ b/frappe/docs/current/api/model/utils/frappe.model.utils.html
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.utils.set_default
+ (doc, key)
+
+
Set is_default property of given doc and unset all others filtered by given key.
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/model/utils/frappe.model.utils.rename_field.html b/frappe/docs/current/api/model/utils/frappe.model.utils.rename_field.html
new file mode 100644
index 0000000000..d8abc8cf4d
--- /dev/null
+++ b/frappe/docs/current/api/model/utils/frappe.model.utils.rename_field.html
@@ -0,0 +1,82 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.utils.rename_field.rename_field
+ (doctype, old_fieldname, new_fieldname)
+
+
This functions assumes that doctype is already synced
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.utils.rename_field.update_property_setters
+ (doctype, old_fieldname, new_fieldname)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.utils.rename_field.update_reports
+ (doctype, old_fieldname, new_fieldname)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.model.utils.rename_field.update_users_report_view_settings
+ (doctype, ref_fieldname, new_fieldname)
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/model/utils/index.html b/frappe/docs/current/api/model/utils/index.html
new file mode 100644
index 0000000000..285965fff4
--- /dev/null
+++ b/frappe/docs/current/api/model/utils/index.html
@@ -0,0 +1,19 @@
+
+
+
+
+
+
Package Contents
+
+{index}
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/model/utils/index.txt b/frappe/docs/current/api/model/utils/index.txt
new file mode 100644
index 0000000000..3887301bf2
--- /dev/null
+++ b/frappe/docs/current/api/model/utils/index.txt
@@ -0,0 +1,2 @@
+frappe.model.utils
+frappe.model.utils.rename_field
\ No newline at end of file
diff --git a/frappe/docs/current/api/modules/frappe.modules.export_file.html b/frappe/docs/current/api/modules/frappe.modules.export_file.html
new file mode 100644
index 0000000000..1d8cf369a6
--- /dev/null
+++ b/frappe/docs/current/api/modules/frappe.modules.export_file.html
@@ -0,0 +1,114 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.modules.export_file.create_folder
+ (module, dt, dn, create_init)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.modules.export_file.create_init_py
+ (module_path, dt, dn)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.modules.export_file.export_doc
+ (doc)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.modules.export_file.export_to_files
+ (record_list=None, record_module=None, verbose=0, create_init=None)
+
+
Export recordlist to files. record list is a list of lists ([doctype],[docname] ) ,
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.modules.export_file.get_module_name
+ (doc)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.modules.export_file.write_document_file
+ (doc, record_module=None, create_init=None)
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/modules/frappe.modules.html b/frappe/docs/current/api/modules/frappe.modules.html
new file mode 100644
index 0000000000..1e1f7aaae4
--- /dev/null
+++ b/frappe/docs/current/api/modules/frappe.modules.html
@@ -0,0 +1,210 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.modules.export_doc
+ (doctype, name, module=None)
+
+
Write a doc to standard path.
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.modules.get_app_publisher
+ (module)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.modules.get_doc_path
+ (module, doctype, name)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.modules.get_doctype_module
+ (doctype)
+
+
Returns Module Def name of given doctype.
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.modules.get_module_app
+ (module)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.modules.get_module_name
+ (doctype, module, prefix=, app=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.modules.get_module_path
+ (module)
+
+
Returns path of the given module
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.modules.load_doctype_module
+ (doctype, module=None, prefix=)
+
+
Returns the module object for given doctype.
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.modules.make_boilerplate
+ (template, doc, opts=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.modules.reload_doc
+ (module, dt=None, dn=None, force=True)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.modules.scrub
+ (txt)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.modules.scrub_dt_dn
+ (dt, dn)
+
+
Returns in lowercase and code friendly names of doctype and name for certain types
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/modules/frappe.modules.import_file.html b/frappe/docs/current/api/modules/frappe.modules.import_file.html
new file mode 100644
index 0000000000..88cbcdb83e
--- /dev/null
+++ b/frappe/docs/current/api/modules/frappe.modules.import_file.html
@@ -0,0 +1,114 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.modules.import_file.get_file_path
+ (module, dt, dn)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.modules.import_file.import_doc
+ (docdict, force=False, data_import=False, pre_process=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.modules.import_file.import_file
+ (module, dt, dn, force=False, pre_process=None)
+
+
Sync a file from txt if modifed, return false if not updated
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.modules.import_file.import_file_by_path
+ (path, force=False, data_import=False, pre_process=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.modules.import_file.import_files
+ (module, dt=None, dn=None, force=False, pre_process=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.modules.import_file.read_doc_from_file
+ (path)
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/modules/frappe.modules.patch_handler.html b/frappe/docs/current/api/modules/frappe.modules.patch_handler.html
new file mode 100644
index 0000000000..3dd0b30bf0
--- /dev/null
+++ b/frappe/docs/current/api/modules/frappe.modules.patch_handler.html
@@ -0,0 +1,193 @@
+
+
+
+
+
+
+
+
+
Class PatchError
+
+
Inherits from exceptions.Exception
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.modules.patch_handler.block_user
+ (block)
+
+
stop/start execution till patch is run
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.modules.patch_handler.check_session_stopped
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.modules.patch_handler.execute_patch
+ (patchmodule, method=None, methodargs=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.modules.patch_handler.executed
+ (patchmodule)
+
+
return True if is executed
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.modules.patch_handler.get_all_patches
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.modules.patch_handler.log
+ (msg)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.modules.patch_handler.reload_doc
+ (args)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.modules.patch_handler.run_all
+ ()
+
+
run all pending patches
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.modules.patch_handler.run_single
+ (patchmodule=None, method=None, methodargs=None, force=False)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.modules.patch_handler.update_patch_log
+ (patchmodule)
+
+
update patch_file in patch log
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/modules/frappe.modules.utils.html b/frappe/docs/current/api/modules/frappe.modules.utils.html
new file mode 100644
index 0000000000..90b9c7dc23
--- /dev/null
+++ b/frappe/docs/current/api/modules/frappe.modules.utils.html
@@ -0,0 +1,117 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.modules.utils.commonify_doclist
+ (doclist, with_comments=1)
+
+
Makes a doclist more readable by extracting common properties.
+This is used for printing Documents in files
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.modules.utils.listfolders
+ (path, only_name=0)
+
+
Returns the list of folders (with paths) in the given path,
+If only_name is set, it returns only the folder names
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.modules.utils.peval_doclist
+ (txt)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.modules.utils.pprint_doclist
+ (doclist, with_comments=1)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.modules.utils.switch_module
+ (dt, dn, to, frm=None, export=None)
+
+
Change the module of the given doctype, if export is true, then also export txt and copy
+code files from src
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.modules.utils.uncommonify_doclist
+ (dl)
+
+
Expands an commonified doclist
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/modules/index.html b/frappe/docs/current/api/modules/index.html
new file mode 100644
index 0000000000..aa3ea6a3d5
--- /dev/null
+++ b/frappe/docs/current/api/modules/index.html
@@ -0,0 +1,19 @@
+
+
+
+
+
+
Package Contents
+
+{index}
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/modules/index.txt b/frappe/docs/current/api/modules/index.txt
new file mode 100644
index 0000000000..f5fd1cfdbc
--- /dev/null
+++ b/frappe/docs/current/api/modules/index.txt
@@ -0,0 +1,5 @@
+frappe.modules.export_file
+frappe.modules
+frappe.modules.import_file
+frappe.modules.patch_handler
+frappe.modules.utils
\ No newline at end of file
diff --git a/frappe/docs/current/api/print/frappe.print.html b/frappe/docs/current/api/print/frappe.print.html
new file mode 100644
index 0000000000..6bfe08cc90
--- /dev/null
+++ b/frappe/docs/current/api/print/frappe.print.html
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/print/index.html b/frappe/docs/current/api/print/index.html
new file mode 100644
index 0000000000..f3cf57299f
--- /dev/null
+++ b/frappe/docs/current/api/print/index.html
@@ -0,0 +1,19 @@
+
+
+
+
+
+
Package Contents
+
+{index}
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/print/index.txt b/frappe/docs/current/api/print/index.txt
new file mode 100644
index 0000000000..1b90f60e66
--- /dev/null
+++ b/frappe/docs/current/api/print/index.txt
@@ -0,0 +1 @@
+frappe.print
\ No newline at end of file
diff --git a/frappe/docs/current/api/utils/frappe.utils.autodoc.html b/frappe/docs/current/api/utils/frappe.utils.autodoc.html
new file mode 100644
index 0000000000..741c76bf22
--- /dev/null
+++ b/frappe/docs/current/api/utils/frappe.utils.autodoc.html
@@ -0,0 +1,152 @@
+
+
+
+
+
Introduction frappe.utils.autodoc
+~~~~~~~~~~~~~~~~~~~~
+
+
Inspect elements of a given module and return its objects
+
+
+
+
+
+
+
+
+
+ frappe.utils.autodoc.automodel
+ (doctype)
+
+
return doctype template
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.autodoc.automodule
+ (name)
+
+
Returns a list of attributes for given module string.
+
+
Attribute Format:
+
+
{
+ "name": [__name__],
+ "type": ["function" or "class"]
+ "args": [inspect.getargspec(value) (for function)]
+ "docs": [__doc__ as markdown]
+}
+
+
+
Parameters:
+
+
+name - Module name as string.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.autodoc.get_class_info
+ (class_obj, module_name)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.autodoc.get_function_info
+ (value)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.autodoc.get_version
+ (name)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.autodoc.parse
+ (docs)
+
+
Parameters:
+
+
Parse docs text into markdown. Will parse directives like - **name** - etc
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.autodoc.strip_leading_tabs
+ (docs)
+
+
Strip leading tabs from doc text.
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/utils/frappe.utils.backups.html b/frappe/docs/current/api/utils/frappe.utils.backups.html
new file mode 100644
index 0000000000..1b05924bcf
--- /dev/null
+++ b/frappe/docs/current/api/utils/frappe.utils.backups.html
@@ -0,0 +1,254 @@
+
+
+
+
+
Introduction This module handles the On Demand Backup utility
+
+
+
+
+
Class BackupGenerator
+
+
This class contains methods to perform On Demand Backup
+
+
To initialize, specify (dbname, user, password, db filename=None, db host="localhost")
+If specifying dbfile name, also append ".sql.gz"
+
+
+
+
+
+
+
+
+
+ __init__
+ (self, db_name, user, password, backup_path_db=None, backup_path_files=None, backup_path_private_files=None, db_host=localhost)
+
+
+
+
+
+
+
+
+
+
+
+ get_backup
+ (self, older_than=24, ignore_files=False, force=False)
+
+
Takes a new dump if existing file is old
+and sends the link to the file as email
+
+
+
+
+
+
+
+
+
+
+ get_recent_backup
+ (self, older_than)
+
+
+
+
+
+
+
+
+
+
+
+ send_email
+ (self)
+
+
Sends the link to backup file located at erpnext/backups
+
+
+
+
+
+
+
+
+
+
+ set_backup_file_name
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ take_dump
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ zip_files
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.backups.backup
+ (with_files=False, backup_path_db=None, backup_path_files=None, quiet=False)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.backups.delete_temp_backups
+ (older_than=24)
+
+
Cleans up the backuplink path directory by deleting files older than 24 hours
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.utils.backups.get_backup
+
+
+
+
+ frappe.utils.backups.get_backup
+ ()
+
+
This function is executed when the user clicks on
+Toos > Download Backup
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.backups.get_backup_path
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.backups.is_file_old
+ (db_file_name, older_than=24)
+
+
Checks if file exists and is older than specified hours
+Returns ->
+True: file does not exist or file is old
+False: file is new
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.backups.new_backup
+ (older_than=6, ignore_files=False, backup_path_db=None, backup_path_files=None, backup_path_private_files=None, force=False)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.backups.scheduled_backup
+ (older_than=6, ignore_files=False, backup_path_db=None, backup_path_files=None, backup_path_private_files=None, force=False)
+
+
this function is called from scheduler
+deletes backups older than 7 days
+takes backup
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/utils/frappe.utils.bench_helper.html b/frappe/docs/current/api/utils/frappe.utils.bench_helper.html
new file mode 100644
index 0000000000..c5a73083df
--- /dev/null
+++ b/frappe/docs/current/api/utils/frappe.utils.bench_helper.html
@@ -0,0 +1,130 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.bench_helper.app_group
+ (ctx, site=False, force=False, verbose=False, profile=False)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.bench_helper.get_app_commands
+ (app)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.bench_helper.get_app_group
+ (app)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.bench_helper.get_app_groups
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.bench_helper.get_apps
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.bench_helper.get_sites
+ (site_arg)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.bench_helper.main
+ ()
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/utils/frappe.utils.boilerplate.html b/frappe/docs/current/api/utils/frappe.utils.boilerplate.html
new file mode 100644
index 0000000000..8cbb19817f
--- /dev/null
+++ b/frappe/docs/current/api/utils/frappe.utils.boilerplate.html
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.boilerplate.make_boilerplate
+ (dest, app_name)
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/utils/frappe.utils.change_log.html b/frappe/docs/current/api/utils/frappe.utils.change_log.html
new file mode 100644
index 0000000000..69630d3a4b
--- /dev/null
+++ b/frappe/docs/current/api/utils/frappe.utils.change_log.html
@@ -0,0 +1,96 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.change_log.get_change_log
+ (user=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.change_log.get_change_log_for_app
+ (app, from_version, to_version)
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.utils.change_log.get_versions
+
+
+
+
+ frappe.utils.change_log.get_versions
+ ()
+
+
Get versions of all installed apps.
+
+
Example:
+
+
{
+ "frappe": {
+ "title": "Frappe Framework",
+ "version": "5.0.0"
+ }
+}
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.utils.change_log.update_last_known_versions
+
+
+
+
+ frappe.utils.change_log.update_last_known_versions
+ ()
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/utils/frappe.utils.csvutils.html b/frappe/docs/current/api/utils/frappe.utils.csvutils.html
new file mode 100644
index 0000000000..7d6eb55572
--- /dev/null
+++ b/frappe/docs/current/api/utils/frappe.utils.csvutils.html
@@ -0,0 +1,203 @@
+
+
+
+
+
+
+
+
+
Class UnicodeWriter
+
+
+
+
+
+
+
+
+
+
+ __init__
+ (self, encoding=utf-8)
+
+
+
+
+
+
+
+
+
+
+
+ getvalue
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ writerow
+ (self, row)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.csvutils.check_record
+ (d)
+
+
check for mandatory, select options, dates. these should ideally be in doclist
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.csvutils.getlink
+ (doctype, name)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.csvutils.import_doc
+ (d, doctype, overwrite, row_idx, submit=False, ignore_links=False)
+
+
import main (non child) document
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.csvutils.read_csv_content
+ (fcontent, ignore_encoding=False)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.csvutils.read_csv_content_from_attached_file
+ (doc)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.csvutils.read_csv_content_from_uploaded_file
+ (ignore_encoding=False)
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.utils.csvutils.send_csv_to_client
+
+
+
+
+ frappe.utils.csvutils.send_csv_to_client
+ (args)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.csvutils.to_csv
+ (data)
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/utils/frappe.utils.data.html b/frappe/docs/current/api/utils/frappe.utils.data.html
new file mode 100644
index 0000000000..0198f26d61
--- /dev/null
+++ b/frappe/docs/current/api/utils/frappe.utils.data.html
@@ -0,0 +1,976 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.data._get_time_zone
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.data.add_days
+ (date, days)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.data.add_months
+ (date, months)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.data.add_to_date
+ (date, years=0, months=0, days=0)
+
+
Adds days to the given date
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.data.add_years
+ (date, years)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.data.cint
+ (s)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.data.comma_and
+ (some_list)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.data.comma_or
+ (some_list)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.data.comma_sep
+ (some_list, pattern)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.data.compare
+ (val1, condition, val2)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.data.convert_utc_to_user_timezone
+ (utc_timestamp)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.data.cstr
+ (s)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.data.date_diff
+ (string_ed_date, string_st_date)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.data.encode
+ (obj, encoding=utf-8)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.data.escape_html
+ (text)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.data.expand_relative_urls
+ (html)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.data.filter_strip_join
+ (some_list, sep)
+
+
given a list, filter None values, strip spaces and join
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.data.flt
+ (s, precision=None)
+
+
Convert to float (ignore commas)
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.data.fmt_money
+ (amount, precision=None, currency=None)
+
+
Convert to string with commas for thousands, millions etc
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.data.format_datetime
+ (datetime_string, format_string=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.data.format_time
+ (txt)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.data.formatdate
+ (string_date=None, format_string=None)
+
+
Convers the given string date to :data:user_format
+ser format specified in defaults
+
+
Examples:
+
+
+dd-mm-yyyy
+mm-dd-yyyy
+dd/mm/yyyy
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.data.get_datetime
+ (datetime_str=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.data.get_datetime_str
+ (datetime_obj)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.data.get_first_day
+ (dt, d_years=0, d_months=0)
+
+
Returns the first day of the month for the date specified by date object
+Also adds d_years and d_months if specified
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.data.get_host_name
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.data.get_last_day
+ (dt)
+
+
Returns last day of the month using:
+get_first_day(dt, 0, 1) + datetime.timedelta(-1)
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.data.get_link_to_form
+ (doctype, name, label=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.data.get_number_format_info
+ (format)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.data.get_time
+ (time_str)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.data.get_time_zone
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.data.get_url
+ (uri=None, full_address=False)
+
+
get app url from request
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.data.get_url_to_form
+ (doctype, name)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.data.get_url_to_list
+ (doctype)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.data.get_user_format
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.data.getdate
+ (string_date=None)
+
+
Coverts string date (yyyy-mm-dd) to datetime.date object
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.data.global_date_format
+ (date)
+
+
returns date as 1 January 2012
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.data.has_common
+ (l1, l2)
+
+
Returns truthy value if there are common elements in lists l1 and l2
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.data.in_words
+ (integer, in_million=True)
+
+
Returns string in words for the given integer.
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.data.is_html
+ (text)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.data.money_in_words
+ (number, main_currency=None, fraction_currency=None)
+
+
Returns string in words with currency and fraction currency.
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.data.now
+ ()
+
+
return current datetime as yyyy-mm-dd hh:mm:ss
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.data.now_datetime
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.data.nowdate
+ ()
+
+
return current date as yyyy-mm-dd
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.data.nowtime
+ ()
+
+
return current time in hh:mm
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.data.parse_val
+ (v)
+
+
Converts to simple datatypes from SQL query results
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.data.pretty_date
+ (iso_datetime)
+
+
Takes an ISO time and returns a string representing how
+long ago the date represents.
+Ported from PrettyDate by John Resig
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.data.quote_urls
+ (html)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.data.quoted
+ (url)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.data.rounded
+ (num, precision=0)
+
+
round method for round halfs to nearest even algorithm aka banker's rounding - compatible with python3
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.data.scrub_urls
+ (html)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.data.strip
+ (val, chars=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.data.strip_html
+ (text)
+
+
removes anything enclosed in and including <>
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.data.time_diff
+ (string_ed_date, string_st_date)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.data.time_diff_in_hours
+ (string_ed_date, string_st_date)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.data.time_diff_in_seconds
+ (string_ed_date, string_st_date)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.data.to_timedelta
+ (time_str)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.data.today
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.data.unique
+ (seq)
+
+
use this instead of list(set()) to preserve order of the original list.
+Thanks to Stackoverflow: http://stackoverflow.com/questions/480214/how-do-you-remove-duplicates-from-a-list-in-python-whilst-preserving-order
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/utils/frappe.utils.dateutils.html b/frappe/docs/current/api/utils/frappe.utils.dateutils.html
new file mode 100644
index 0000000000..6f62182159
--- /dev/null
+++ b/frappe/docs/current/api/utils/frappe.utils.dateutils.html
@@ -0,0 +1,82 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.dateutils.datetime_in_user_format
+ (date_time)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.dateutils.get_user_date_format
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.dateutils.parse_date
+ (date)
+
+
tries to parse given date to system's format i.e. yyyy-mm-dd. returns a string
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.dateutils.user_to_str
+ (date, date_format=None)
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/utils/frappe.utils.doctor.html b/frappe/docs/current/api/utils/frappe.utils.doctor.html
new file mode 100644
index 0000000000..051e5ceeef
--- /dev/null
+++ b/frappe/docs/current/api/utils/frappe.utils.doctor.html
@@ -0,0 +1,213 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.doctor.celery_doctor
+ (site=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.doctor.check_if_workers_online
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.doctor.doctor
+ ()
+
+
Prints diagnostic information for the scheduler
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.doctor.dump_queue_status
+ (site=None)
+
+
Dumps pending events and tasks per queue
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.doctor.get_pending_task_count
+ ()
+
+
Get count of pending tasks
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.doctor.get_queues
+ (site=None)
+
+
Returns the name of queues where frappe enqueues tasks as per the configuration
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.doctor.get_redis_conn
+ ()
+
+
Returns the redis connection that celery would use
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.doctor.get_running_tasks
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.doctor.get_task_body
+ (taskstr)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.doctor.get_task_count_for_queue
+ (queue)
+
+
For a given queue, returns the count of every pending task and aggregate of
+events pending
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.doctor.get_timedout_locks
+ ()
+
+
Get list of stale locks from all sites
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.doctor.purge_pending_tasks
+ (event=all)
+
+
Purge tasks of the event event type. Passing 'all' will not purge all
+events but of the all event type, ie. the ones that are enqueued every five
+mintues and would any leave daily, hourly and weekly tasks
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/utils/frappe.utils.error.html b/frappe/docs/current/api/utils/frappe.utils.error.html
new file mode 100644
index 0000000000..07d37337cc
--- /dev/null
+++ b/frappe/docs/current/api/utils/frappe.utils.error.html
@@ -0,0 +1,98 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.error.clear_old_snapshots
+ ()
+
+
Clear snapshots that are older than a month
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.error.collect_error_snapshots
+ ()
+
+
Scheduled task to collect error snapshots from files and push into Error Snapshot table
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.error.get_error_snapshot_path
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.error.get_snapshot
+ (exception, context=10)
+
+
Return a dict describing a given traceback (based on cgitb.text)
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.error.make_error_snapshot
+ (exception)
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/utils/frappe.utils.file_lock.html b/frappe/docs/current/api/utils/frappe.utils.file_lock.html
new file mode 100644
index 0000000000..e4c11f76da
--- /dev/null
+++ b/frappe/docs/current/api/utils/frappe.utils.file_lock.html
@@ -0,0 +1,97 @@
+
+
+
+
+
+
+
+
+
Class LockTimeoutError
+
+
Inherits from exceptions.Exception
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.file_lock.check_lock
+ (path)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.file_lock.create_lock
+ (name)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.file_lock.delete_lock
+ (name)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.file_lock.get_lock_path
+ (name)
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/utils/frappe.utils.file_manager.html b/frappe/docs/current/api/utils/frappe.utils.file_manager.html
new file mode 100644
index 0000000000..5cce4577d6
--- /dev/null
+++ b/frappe/docs/current/api/utils/frappe.utils.file_manager.html
@@ -0,0 +1,401 @@
+
+
+
+
+
+
+
+
+
Class MaxFileSizeReachedError
+
+
Inherits from frappe.exceptions.ValidationError
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.file_manager.check_max_file_size
+ (content)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.file_manager.delete_file
+ (path)
+
+
Delete file from public folder
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.file_manager.delete_file_data_content
+ (doc, only_thumbnail=False)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.file_manager.delete_file_from_filesystem
+ (doc, only_thumbnail=False)
+
+
Delete file, thumbnail from File document
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.file_manager.extract_images_from_doc
+ (doc, fieldname)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.file_manager.extract_images_from_html
+ (doc, content)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.file_manager.get_content_hash
+ (content)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.file_manager.get_file
+ (fname)
+
+
Returns [file_name, content] for given file name fname
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.file_manager.get_file_data_from_hash
+ (content_hash, is_private=0)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.file_manager.get_file_name
+ (fname, optional_suffix)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.file_manager.get_file_path
+ (file_name)
+
+
Returns file path from given file name
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.file_manager.get_file_url
+ (file_data_name)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.file_manager.get_random_filename
+ (extn=None, content_type=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.file_manager.get_uploaded_content
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.file_manager.remove_all
+ (dt, dn)
+
+
remove all files in a transaction
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.file_manager.remove_file
+ (fid, attached_to_doctype=None, attached_to_name=None)
+
+
Remove file and File entry
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.file_manager.remove_file_by_url
+ (file_url, doctype=None, name=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.file_manager.save_file
+ (fname, content, dt, dn, folder=None, decode=False, is_private=0)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.file_manager.save_file_on_filesystem
+ (fname, content, content_type=None, is_private=0)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.file_manager.save_uploaded
+ (dt, dn, folder, is_private)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.file_manager.save_url
+ (file_url, dt, dn, folder)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.file_manager.upload
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.file_manager.write_file
+ (content, fname, is_private=0)
+
+
write file to disk with a random name (to compare)
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/utils/frappe.utils.fixtures.html b/frappe/docs/current/api/utils/frappe.utils.fixtures.html
new file mode 100644
index 0000000000..66c633d4b5
--- /dev/null
+++ b/frappe/docs/current/api/utils/frappe.utils.fixtures.html
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.fixtures.export_fixtures
+ ()
+
+
Export fixtures as JSON to [app]/fixtures
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.fixtures.import_custom_scripts
+ (app)
+
+
Import custom scripts from [app]/fixtures/custom_scripts
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.fixtures.sync_fixtures
+ (app=None)
+
+
Import, overwrite fixtures from [app]/fixtures
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/utils/frappe.utils.formatters.html b/frappe/docs/current/api/utils/frappe.utils.formatters.html
new file mode 100644
index 0000000000..746c4f5b1f
--- /dev/null
+++ b/frappe/docs/current/api/utils/frappe.utils.formatters.html
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.formatters.format_value
+ (value, df, doc=None, currency=None)
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/utils/frappe.utils.html b/frappe/docs/current/api/utils/frappe.utils.html
new file mode 100644
index 0000000000..d8534b5f4e
--- /dev/null
+++ b/frappe/docs/current/api/utils/frappe.utils.html
@@ -0,0 +1,743 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.call_hook_method
+ (hook)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.decode_dict
+ (d, encoding=utf-8)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.dict_to_str
+ (args, sep=&)
+
+
Converts a dictionary to URL
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.encode_dict
+ (d, encoding=utf-8)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.esc
+ (s, esc_chars)
+
+
Escape special characters
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.execute_in_shell
+ (cmd, verbose=0)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.extract_email_id
+ (email)
+
+
fetch only the email part of the email id
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.getCSVelement
+ (v)
+
+
Returns the CSV value of v, For example:
+
+
+apple becomes "apple"
+hi"there becomes "hi""there"
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.get_backups_path
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.get_bench_path
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.get_common
+ (d1, d2)
+
+
returns (list of keys) the common part of two dicts
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.get_common_dict
+ (d1, d2)
+
+
return common dictionary of d1 and d2
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.get_defaults
+ (key=None)
+
+
Get dictionary of default values from the defaults, or a value if key is passed
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.get_diff_dict
+ (d1, d2)
+
+
return common dictionary of d1 and d2
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.get_disk_usage
+ ()
+
+
get disk usage of files folder
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.get_file_timestamp
+ (fn)
+
+
Returns timestamp of the given file
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.get_files_path
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.get_formatted_email
+ (user)
+
+
get email id of user formatted as: John Doe <johndoe@example.com>
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.get_fullname
+ (user=None)
+
+
get the full name (first name + last name) of the user from User
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.get_gravatar
+ (email)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.get_hook_method
+ (hook_name, fallback=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.get_html_format
+ (print_path)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.get_path
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.get_request_session
+ (max_retries=3)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.get_request_site_address
+ (full_address=False)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.get_site_base_path
+ (sites_dir=None, hostname=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.get_site_name
+ (hostname)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.get_site_path
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.get_sites
+ (sites_path=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.get_test_client
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.get_traceback
+ ()
+
+
Returns the traceback of the Exception
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.is_markdown
+ (text)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.log
+ (event, details)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.make_esc
+ (esc_chars)
+
+
Function generator for Escaping special characters
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.pprint_dict
+ (d, level=1, no_blanks=True)
+
+
Pretty print a dictionary with indents
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.random_string
+ (length)
+
+
generate a random string
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.remove_blanks
+ (d)
+
+
Returns d with empty ('' or None) values stripped
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.set_default
+ (key, val)
+
+
Set / add a default value to defaults`
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.split_emails
+ (txt)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.strip_html_tags
+ (text)
+
+
Remove html tags from text
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.touch_file
+ (path)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.unesc
+ (s, esc_chars)
+
+
UnEscape special characters
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.update_progress_bar
+ (txt, i, l)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.validate_email_add
+ (email_str, throw=False)
+
+
Validates the email string
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.watch
+ (path, handler=None, debug=True)
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/utils/frappe.utils.image.html b/frappe/docs/current/api/utils/frappe.utils.image.html
new file mode 100644
index 0000000000..1c7e9a13db
--- /dev/null
+++ b/frappe/docs/current/api/utils/frappe.utils.image.html
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.image.resize_images
+ (path, maxdim=700)
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/utils/frappe.utils.install.html b/frappe/docs/current/api/utils/frappe.utils.install.html
new file mode 100644
index 0000000000..1b31421e10
--- /dev/null
+++ b/frappe/docs/current/api/utils/frappe.utils.install.html
@@ -0,0 +1,114 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.install.add_country_and_currency
+ (name, country)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.install.after_install
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.install.before_install
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.install.before_tests
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.install.get_admin_password
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.install.import_country_and_currency
+ ()
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/utils/frappe.utils.jinja.html b/frappe/docs/current/api/utils/frappe.utils.jinja.html
new file mode 100644
index 0000000000..c326e672bc
--- /dev/null
+++ b/frappe/docs/current/api/utils/frappe.utils.jinja.html
@@ -0,0 +1,130 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.jinja.get_allowed_functions_for_jenv
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.jinja.get_jenv
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.jinja.get_jloader
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.jinja.get_template
+ (path)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.jinja.render_include
+ (content)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.jinja.render_template
+ (template, context, is_path=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.jinja.set_filters
+ (jenv)
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/utils/frappe.utils.make_random.html b/frappe/docs/current/api/utils/frappe.utils.make_random.html
new file mode 100644
index 0000000000..1ccfd6e821
--- /dev/null
+++ b/frappe/docs/current/api/utils/frappe.utils.make_random.html
@@ -0,0 +1,82 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.make_random.add_random_children
+ (doc, fieldname, rows, randomize, unique=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.make_random.can_make
+ (doctype)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.make_random.get_random
+ (doctype, filters=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.make_random.how_many
+ (doctype)
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/utils/frappe.utils.minify.html b/frappe/docs/current/api/utils/frappe.utils.minify.html
new file mode 100644
index 0000000000..2c63fe202d
--- /dev/null
+++ b/frappe/docs/current/api/utils/frappe.utils.minify.html
@@ -0,0 +1,234 @@
+
+
+
+
+
+
+
+
+
Class JavascriptMinify
+
+
Inherits from __builtin__.object
+
+
+
+
+
+
+
+
+
+
+ _action
+ (self, action)
+
+
do something! What you do is determined by the argument:
+1 Output A. Copy B to A. Get the next B.
+2 Copy B to A. Get the next B. (Delete A).
+3 Get the next B. (Delete B).
+action treats a string as a single character. Wow!
+action recognizes a regular expression if it is preceded by ( or , or =.
+
+
+
+
+
+
+
+
+
+
+ _get
+ (self)
+
+
return the next character from stdin. Watch out for lookahead. If
+the character is a control character, translate it to a space or
+linefeed.
+
+
+
+
+
+
+
+
+
+
+ _jsmin
+ (self)
+
+
Copy the input to the output, deleting the characters which are
+insignificant to JavaScript. Comments will be removed. Tabs will be
+replaced with spaces. Carriage returns will be replaced with linefeeds.
+Most spaces and linefeeds will be removed.
+
+
+
+
+
+
+
+
+
+
+ _next
+ (self)
+
+
get the next character, excluding comments. peek() is used to see
+if an unescaped '/' is followed by a '/' or '*'.
+
+
+
+
+
+
+
+
+
+
+ _outA
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ _outB
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ _peek
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ minify
+ (self, instream, outstream)
+
+
+
+
+
+
+
+
+
+
+
+
+
Class UnterminatedComment
+
+
Inherits from exceptions.Exception
+
+
+
+
+
+
+
+
+
+
+
+
Class UnterminatedRegularExpression
+
+
Inherits from exceptions.Exception
+
+
+
+
+
+
+
+
+
+
+
+
Class UnterminatedStringLiteral
+
+
Inherits from exceptions.Exception
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.minify.isAlphanum
+ (c)
+
+
return true if the character is a letter, digit, underscore,
+dollar sign, or non-ASCII character.
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.minify.jsmin
+ (js)
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/utils/frappe.utils.momentjs.html b/frappe/docs/current/api/utils/frappe.utils.momentjs.html
new file mode 100644
index 0000000000..6d81533478
--- /dev/null
+++ b/frappe/docs/current/api/utils/frappe.utils.momentjs.html
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.momentjs.get_all_timezones
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.momentjs.update
+ (tz, out)
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/utils/frappe.utils.nestedset.html b/frappe/docs/current/api/utils/frappe.utils.nestedset.html
new file mode 100644
index 0000000000..59f80caec6
--- /dev/null
+++ b/frappe/docs/current/api/utils/frappe.utils.nestedset.html
@@ -0,0 +1,319 @@
+
+
+
+
+
+
+
+
+
Class NestedSet
+
+
Inherits from frappe.model.document.Document
+
+
+
+
+
+
+
+
+
+
+ after_rename
+ (self, olddn, newdn, merge=False)
+
+
+
+
+
+
+
+
+
+
+
+ before_rename
+ (self, olddn, newdn, merge=False, group_fname=is_group)
+
+
+
+
+
+
+
+
+
+
+
+ get_ancestors
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ on_trash
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ on_update
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ validate_ledger
+ (self, group_identifier=is_group)
+
+
+
+
+
+
+
+
+
+
+
+ validate_one_root
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+
+
Class NestedSetChildExistsError
+
+
Inherits from frappe.exceptions.ValidationError
+
+
+
+
+
+
+
+
+
+
+
+
Class NestedSetInvalidMergeError
+
+
Inherits from frappe.exceptions.ValidationError
+
+
+
+
+
+
+
+
+
+
+
+
Class NestedSetMultipleRootsError
+
+
Inherits from frappe.exceptions.ValidationError
+
+
+
+
+
+
+
+
+
+
+
+
Class NestedSetRecursionError
+
+
Inherits from frappe.exceptions.ValidationError
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.nestedset.get_ancestors_of
+ (doctype, name)
+
+
Get ancestor elements of a DocType with a tree structure
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.nestedset.get_root_of
+ (doctype)
+
+
Get root element of a DocType with a tree structure
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.nestedset.rebuild_node
+ (doctype, parent, left, parent_field)
+
+
reset lft, rgt and recursive call for all children
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.nestedset.rebuild_tree
+ (doctype, parent_field)
+
+
call rebuild_node for all root nodes
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.nestedset.update_add_node
+ (doc, parent, parent_field)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.nestedset.update_move_node
+ (doc, parent_field)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.nestedset.update_nsm
+ (doc)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.nestedset.validate_loop
+ (doctype, name, lft, rgt)
+
+
check if item not an ancestor (loop)
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/utils/frappe.utils.oauth.html b/frappe/docs/current/api/utils/frappe.utils.oauth.html
new file mode 100644
index 0000000000..0761329370
--- /dev/null
+++ b/frappe/docs/current/api/utils/frappe.utils.oauth.html
@@ -0,0 +1,225 @@
+
+
+
+
+
+
+
+
+
Class SignupDisabledError
+
+
Inherits from frappe.exceptions.PermissionError
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.oauth.get_first_name
+ (data)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.oauth.get_info_via_oauth
+ (provider, code, decoder=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.oauth.get_last_name
+ (data)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.oauth.get_oauth2_authorize_url
+ (provider)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.oauth.get_oauth2_flow
+ (provider)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.oauth.get_oauth2_providers
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.oauth.get_oauth_keys
+ (provider)
+
+
get clientid and client secret from database or conf
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.oauth.get_redirect_uri
+ (provider)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.oauth.login_oauth_user
+ (data=None, provider=None, state=None, email_id=None, key=None, generate_login_token=False)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.oauth.login_via_oauth2
+ (provider, code, state, decoder=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.oauth.redirect_post_login
+ (desk_user)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.oauth.update_oauth_user
+ (user, data, provider)
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/utils/frappe.utils.pdf.html b/frappe/docs/current/api/utils/frappe.utils.pdf.html
new file mode 100644
index 0000000000..f81c0ebf37
--- /dev/null
+++ b/frappe/docs/current/api/utils/frappe.utils.pdf.html
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.pdf.get_pdf
+ (html, options=None)
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/utils/frappe.utils.redis_wrapper.html b/frappe/docs/current/api/utils/frappe.utils.redis_wrapper.html
new file mode 100644
index 0000000000..9348114612
--- /dev/null
+++ b/frappe/docs/current/api/utils/frappe.utils.redis_wrapper.html
@@ -0,0 +1,229 @@
+
+
+
+
+
+
+
+
+
Class RedisWrapper
+
+
Inherits from redis.client.Redis
+
+
Redis client that will automatically prefix conf.db_name
+
+
+
+
+
+
+
+
+
+ delete_key
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ delete_keys
+ (self, key)
+
+
Delete keys with wildcard *.
+
+
+
+
+
+
+
+
+
+
+ delete_value
+ (self, keys, user=None, make_keys=True)
+
+
Delete value, list of values.
+
+
+
+
+
+
+
+
+
+
+ get_all
+ (self, key)
+
+
+
+
+
+
+
+
+
+
+
+ get_keys
+ (self, key)
+
+
Return keys starting with key.
+
+
+
+
+
+
+
+
+
+
+ get_value
+ (self, key, generator=None, user=None, expires=False)
+
+
Returns cache value. If not found and generator function is
+given, it will call the generator.
+
+
param key: Cache key.
+param generator: Function to be called to generate a value if None is returned.
+param expires: If the key is supposed to be with an expiry, don't store it in frappe.local
+
+
+
+
+
+
+
+
+
+
+ hdel
+ (self, name, key)
+
+
+
+
+
+
+
+
+
+
+
+ hdel_keys
+ (self, name_starts_with, key)
+
+
Delete hash names with wildcard * and key
+
+
+
+
+
+
+
+
+
+
+ hget
+ (self, name, key, generator=None)
+
+
+
+
+
+
+
+
+
+
+
+ hkeys
+ (self, name)
+
+
+
+
+
+
+
+
+
+
+
+ hset
+ (self, name, key, value)
+
+
+
+
+
+
+
+
+
+
+
+ make_key
+ (self, key, user=None)
+
+
+
+
+
+
+
+
+
+
+
+ set_value
+ (self, key, val, user=None, expires_in_sec=None)
+
+
Sets cache value.
+
+
Parameters:
+
+
+key - Cache key
+val - Value to be cached
+user - Prepends key with User
+expires_in_sec - Expire value of this key in X seconds
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/utils/frappe.utils.response.html b/frappe/docs/current/api/utils/frappe.utils.response.html
new file mode 100644
index 0000000000..ebf1652825
--- /dev/null
+++ b/frappe/docs/current/api/utils/frappe.utils.response.html
@@ -0,0 +1,226 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.response.as_csv
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.response.as_json
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.response.as_page
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.response.as_raw
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.response.build_response
+ (response_type=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.response.download_backup
+ (path)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.response.download_private_file
+ (path)
+
+
Checks permissions and sends back private file
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.response.handle_session_stopped
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.response.json_handler
+ (obj)
+
+
serialize non-serializable data for json
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.response.make_logs
+ (response=None)
+
+
make strings for msgprint and errprint
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.response.redirect
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.response.report_error
+ (status_code)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.response.send_private_file
+ (path)
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/utils/frappe.utils.scheduler.html b/frappe/docs/current/api/utils/frappe.utils.scheduler.html
new file mode 100644
index 0000000000..c7fb5b8c65
--- /dev/null
+++ b/frappe/docs/current/api/utils/frappe.utils.scheduler.html
@@ -0,0 +1,199 @@
+
+
+
+
+
Introduction Events:
+ always
+ daily
+ monthly
+ weekly
+
+
+
+
+
+
+
+
+
+ frappe.utils.scheduler.disable_scheduler
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.scheduler.enable_scheduler
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.scheduler.enqueue_applicable_events
+ (site, nowtime, last)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.scheduler.enqueue_events
+ (site)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.scheduler.get_enabled_scheduler_events
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.scheduler.get_error_report
+ (from_date=None, to_date=None, limit=10)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.scheduler.get_errors
+ (from_date, to_date, limit)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.scheduler.is_scheduler_disabled
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.scheduler.log
+ (method, message=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.scheduler.toggle_scheduler
+ (enable)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.scheduler.trigger
+ (site, event, now=False)
+
+
trigger method in startup.schedule_handler
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/utils/frappe.utils.sel.html b/frappe/docs/current/api/utils/frappe.utils.sel.html
new file mode 100644
index 0000000000..4534a70c3c
--- /dev/null
+++ b/frappe/docs/current/api/utils/frappe.utils.sel.html
@@ -0,0 +1,418 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.sel.add_child
+ (fieldname)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.sel.close
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.sel.done_add_child
+ (fieldname)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.sel.execute_script
+ (js)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.sel.find
+ (selector, everywhere=False)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.sel.get
+ (url)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.sel.get_localhost
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.sel.get_wait
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.sel.go_to_module
+ (module_name, item=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.sel.login
+ (wait_for_id=#page-desktop)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.sel.new_doc
+ (module, doctype)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.sel.primary_action
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.sel.scroll_to
+ (selector)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.sel.set_field
+ (fieldname, value, fieldtype=input)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.sel.set_input
+ (selector, text, key=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.sel.set_select
+ (fieldname, value)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.sel.signal_handler
+ (signal, frame)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.sel.start
+ (verbose=None, driver=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.sel.start_test_server
+ (verbose)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.sel.wait
+ (selector, everywhere=False)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.sel.wait_for_ajax
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.sel.wait_for_page
+ (name)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.sel.wait_for_state
+ (state)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.sel.wait_till_clickable
+ (selector)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.sel.wait_till_visible
+ (selector)
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/utils/frappe.utils.setup_docs.html b/frappe/docs/current/api/utils/frappe.utils.setup_docs.html
new file mode 100644
index 0000000000..c58687e8a9
--- /dev/null
+++ b/frappe/docs/current/api/utils/frappe.utils.setup_docs.html
@@ -0,0 +1,239 @@
+
+
+
+
+
Introduction Automatically setup docs for a project
+
+
Call from command line:
+
+
bench setup-docs app path
+
+
+
+
+
+
Class setup_docs
+
+
Inherits from __builtin__.object
+
+
+
+
+
+
+
+
+
+
+ __init__
+ (self, app)
+
+
Generate source templates for models reference and module API
+and templates at templates/autodoc
+
+
+
+
+
+
+
+
+
+
+ build
+ (self, docs_version)
+
+
Build templates for docs models and Python API
+
+
+
+
+
+
+
+
+
+
+ build_user_docs
+ (self)
+
+
Build templates for user docs pages, if missing.
+
+
+
+
+
+
+
+
+
+
+ copy_assets
+ (self)
+
+
Copy jquery, bootstrap and other assets to files
+
+
+
+
+
+
+
+
+
+
+ is_py_module
+ (self, basepath, folders, files)
+
+
+
+
+
+
+
+
+
+
+
+ make_docs
+ (self, target, local=False)
+
+
+
+
+
+
+
+
+
+
+
+ make_folder
+ (self, path, template=None, context=None)
+
+
+
+
+
+
+
+
+
+
+
+ make_home_pages
+ (self)
+
+
Make standard home pages for docs, developer docs, api and models
+from templates
+
+
+
+
+
+
+
+
+
+
+ setup_app_context
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ sync_docs
+ (self)
+
+
Sync docs from /docs folder to Web Page .
+
+
Called as bench --site [sitename] sync-docs [appname]
+
+
+
+
+
+
+
+
+
+
+ update_index_txt
+ (self, path)
+
+
+
+
+
+
+
+
+
+
+
+ write_files
+ (self)
+
+
render templates and write files to target folder
+
+
+
+
+
+
+
+
+
+
+ write_model_file
+ (self, basepath, module, doctype)
+
+
+
+
+
+
+
+
+
+
+
+ write_modules
+ (self, basepath, folders, files)
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/utils/frappe.utils.user.html b/frappe/docs/current/api/utils/frappe.utils.user.html
new file mode 100644
index 0000000000..e2a711de74
--- /dev/null
+++ b/frappe/docs/current/api/utils/frappe.utils.user.html
@@ -0,0 +1,362 @@
+
+
+
+
+
+
+
+
+
Class User
+
+
A user permission object can be accessed as frappe.get_user()
+
+
+
+
+
+
+
+
+
+ __init__
+ (self, name=)
+
+
+
+
+
+
+
+
+
+
+
+ _get
+ (self, key)
+
+
+
+
+
+
+
+
+
+
+
+ build_doctype_map
+ (self)
+
+
build map of special doctype properties
+
+
+
+
+
+
+
+
+
+
+ build_perm_map
+ (self)
+
+
build map of permissions at level 0
+
+
+
+
+
+
+
+
+
+
+ build_permissions
+ (self)
+
+
build lists of what the user can read / write / create
+quirks:
+ readonly => Not in Search
+ in create => Not in create
+
+
+
+
+
+
+
+
+
+
+ get_block_modules
+ (self)
+
+
Returns list of blocked modules
+
+
+
+
+
+
+
+
+
+
+ get_can_read
+ (self)
+
+
return list of doctypes that the user can read
+
+
+
+
+
+
+
+
+
+
+ get_defaults
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ get_roles
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ load_user
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ setup_user
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ update_recent
+ (self, dt, dn)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.user.add_role
+ (user, role)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.user.add_system_manager
+ (email, first_name=None, last_name=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.user.get_enabled_system_users
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.user.get_fullname_and_avatar
+ (user)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.user.get_roles
+ (user=None, with_standard=True)
+
+
get roles of current user
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.user.get_system_managers
+ (only_name=False)
+
+
returns all system manager's user details
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.user.get_user_fullname
+ (user)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.user.get_users
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.user.is_system_user
+ (username)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.user.is_website_user
+ ()
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/utils/frappe.utils.verified_command.html b/frappe/docs/current/api/utils/frappe.utils.verified_command.html
new file mode 100644
index 0000000000..fe7e9f10fc
--- /dev/null
+++ b/frappe/docs/current/api/utils/frappe.utils.verified_command.html
@@ -0,0 +1,136 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.verified_command.get_secret
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.verified_command.get_signature
+ (params, nonce, secret=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.verified_command.get_signed_params
+ (params)
+
+
Sign a url by appending &_signature=xxxxx to given params (string or dict).
+
+
Parameters:
+
+
+params - String or dict of parameters.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.verified_command.get_url
+ (cmd, params, nonce=None, secret=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.verified_command.get_url_using_doc
+ (doc, cmd)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.verified_command.verify_request
+ ()
+
+
Verify if the incoming signed request if it is correct.
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.utils.verified_command.verify_using_doc
+ (doc, signature, cmd)
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/utils/index.html b/frappe/docs/current/api/utils/index.html
new file mode 100644
index 0000000000..285965fff4
--- /dev/null
+++ b/frappe/docs/current/api/utils/index.html
@@ -0,0 +1,19 @@
+
+
+
+
+
+
Package Contents
+
+{index}
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/utils/index.txt b/frappe/docs/current/api/utils/index.txt
new file mode 100644
index 0000000000..c174e90b9c
--- /dev/null
+++ b/frappe/docs/current/api/utils/index.txt
@@ -0,0 +1,31 @@
+frappe.utils.autodoc
+frappe.utils.backups
+frappe.utils.bench_helper
+frappe.utils.boilerplate
+frappe.utils.change_log
+frappe.utils.csvutils
+frappe.utils.data
+frappe.utils.dateutils
+frappe.utils.doctor
+frappe.utils.error
+frappe.utils.file_lock
+frappe.utils.file_manager
+frappe.utils.fixtures
+frappe.utils.formatters
+frappe.utils
+frappe.utils.image
+frappe.utils.install
+frappe.utils.jinja
+frappe.utils.make_random
+frappe.utils.minify
+frappe.utils.momentjs
+frappe.utils.nestedset
+frappe.utils.oauth
+frappe.utils.pdf
+frappe.utils.redis_wrapper
+frappe.utils.response
+frappe.utils.scheduler
+frappe.utils.sel
+frappe.utils.setup_docs
+frappe.utils.user
+frappe.utils.verified_command
\ No newline at end of file
diff --git a/frappe/docs/current/api/website/frappe.website.context.html b/frappe/docs/current/api/website/frappe.website.context.html
new file mode 100644
index 0000000000..9ebe76b9be
--- /dev/null
+++ b/frappe/docs/current/api/website/frappe.website.context.html
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.website.context.add_metatags
+ (context)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.website.context.build_context
+ (context)
+
+
get_context method of doc or module is supposed to render content templates and push it into context
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.website.context.get_context
+ (path, args=None)
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/website/frappe.website.html b/frappe/docs/current/api/website/frappe.website.html
new file mode 100644
index 0000000000..faf44f38ad
--- /dev/null
+++ b/frappe/docs/current/api/website/frappe.website.html
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/website/frappe.website.render.html b/frappe/docs/current/api/website/frappe.website.render.html
new file mode 100644
index 0000000000..0b45cee97b
--- /dev/null
+++ b/frappe/docs/current/api/website/frappe.website.render.html
@@ -0,0 +1,273 @@
+
+
+
+
+
+
+
+
+
Class PageNotFoundError
+
+
Inherits from exceptions.Exception
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.website.render.add_csrf_token
+ (data)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.website.render.build
+ (path)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.website.render.build_json
+ (path)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.website.render.build_page
+ (path)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.website.render.build_response
+ (path, data, http_status_code, headers=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.website.render.clear_cache
+ (path=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.website.render.get_doctype_from_path
+ (path)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.website.render.is_ajax
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.website.render.render
+ (path, http_status_code=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.website.render.render_403
+ (e, pathname)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.website.render.render_page
+ (path)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.website.render.render_page_by_language
+ (path)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.website.render.resolve_from_map
+ (path)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.website.render.resolve_path
+ (path)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.website.render.set_content_type
+ (response, data, path)
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/website/frappe.website.router.html b/frappe/docs/current/api/website/frappe.website.router.html
new file mode 100644
index 0000000000..e46b89d279
--- /dev/null
+++ b/frappe/docs/current/api/website/frappe.website.router.html
@@ -0,0 +1,166 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.website.router.build_route
+ (path)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.website.router.clear_sitemap
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.website.router.get_generator_route
+ (path)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.website.router.get_generator_routes
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.website.router.get_page_route
+ (path)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.website.router.get_pages
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.website.router.get_route_info
+ (path)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.website.router.process_generators
+ (func)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.website.router.resolve_route
+ (path)
+
+
Returns the page route object based on searching in pages and generators.
+The www folder is also a part of generator Web Page .
+
+
The only exceptions are /about and /contact these will be searched in Web Pages
+first before checking the standard pages.
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/website/frappe.website.statics.html b/frappe/docs/current/api/website/frappe.website.statics.html
new file mode 100644
index 0000000000..ab37c5ce22
--- /dev/null
+++ b/frappe/docs/current/api/website/frappe.website.statics.html
@@ -0,0 +1,203 @@
+
+
+
+
+
+
+
+
+
Class sync
+
+
Inherits from __builtin__.object
+
+
+
+
+
+
+
+
+
+
+ __init__
+ (self, verbose=False, path=None)
+
+
+
+
+
+
+
+
+
+
+
+ cleanup
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ get_index_txt
+ (self, basepath, files)
+
+
+
+
+
+
+
+
+
+
+
+ get_title
+ (self, fpath, content)
+
+
+
+
+
+
+
+
+
+
+
+ start
+ (self, rebuild=False, path=www, apps=None)
+
+
+
+
+
+
+
+
+
+
+
+ sync_alphabetically
+ (self, basepath, folders, files, app)
+
+
+
+
+
+
+
+
+
+
+
+ sync_file
+ (self, fname, template_path, priority, app)
+
+
+
+
+
+
+
+
+
+
+
+ sync_folder
+ (self, basepath, folders, files, app)
+
+
+
+
+
+
+
+
+
+
+
+ sync_for_app
+ (self, app)
+
+
+
+
+
+
+
+
+
+
+
+ sync_index_page
+ (self, basepath, files, app)
+
+
+
+
+
+
+
+
+
+
+
+ sync_using_given_index
+ (self, basepath, folders, files, app)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.website.statics.sync_statics
+ (rebuild=False)
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/website/frappe.website.template.html b/frappe/docs/current/api/website/frappe.website.template.html
new file mode 100644
index 0000000000..6c55adf387
--- /dev/null
+++ b/frappe/docs/current/api/website/frappe.website.template.html
@@ -0,0 +1,147 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.website.template.add_hero
+ (out, context)
+
+
Add a hero element if specified in content or hooks.
+Hero elements get full page width.
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.website.template.add_index
+ (out, context)
+
+
Add index, next button if {index}, {next} is present.
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.website.template.build_template
+ (context)
+
+
Returns a dict of block name and its rendered content
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.website.template.render_blocks
+ (template_path, out, context)
+
+
Build the template block by block from the main template.
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.website.template.separate_style_and_script
+ (out, context)
+
+
Extract style and script tags into separate blocks
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.website.template.set_breadcrumbs
+ (out, context)
+
+
Build breadcrumbs template (deprecated)
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.website.template.set_sidebar
+ (out, context)
+
+
Include sidebar (deprecated)
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.website.template.set_title_and_header
+ (out, context)
+
+
Extract and set title and header from content or context.
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/website/frappe.website.utils.html b/frappe/docs/current/api/website/frappe.website.utils.html
new file mode 100644
index 0000000000..43bca203f3
--- /dev/null
+++ b/frappe/docs/current/api/website/frappe.website.utils.html
@@ -0,0 +1,242 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.website.utils.abs_url
+ (path)
+
+
Deconstructs and Reconstructs a URL into an absolute URL or a URL relative from root '/'
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.website.utils.can_cache
+ (no_cache=False)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.website.utils.cleanup_page_name
+ (title)
+
+
make page name from title
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.website.utils.convert_to_hex
+ (channel_value)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.website.utils.delete_page_cache
+ (path)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.website.utils.detect_color_format
+ (color)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.website.utils.find_first_image
+ (html)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.website.utils.format_color
+ (r, g, b, a, color_format)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.website.utils.get_comment_list
+ (doctype, name)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.website.utils.get_full_index
+ (route=None, doctype=Web Page, extn=False)
+
+
Returns full index of the website (on Web Page) upto the n-th level
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.website.utils.get_home_page
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.website.utils.get_shade
+ (color, percent)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.website.utils.get_shade_for_channel
+ (channel_value, percent)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.website.utils.is_signup_enabled
+ ()
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/website/frappe.website.website_generator.html b/frappe/docs/current/api/website/frappe.website.website_generator.html
new file mode 100644
index 0000000000..1de71c4e7b
--- /dev/null
+++ b/frappe/docs/current/api/website/frappe.website.website_generator.html
@@ -0,0 +1,357 @@
+
+
+
+
+
+
+
+
+
Class WebsiteGenerator
+
+
Inherits from frappe.model.document.Document
+
+
+
+
+
+
+
+
+
+
+ after_rename
+ (self, olddn, newdn, merge)
+
+
+
+
+
+
+
+
+
+
+
+ autoname
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ before_rename
+ (self, oldname, name, merge)
+
+
+
+
+
+
+
+
+
+
+
+ clear_cache
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ get_children
+ (self, context=None)
+
+
+
+
+
+
+
+
+
+
+
+ get_children_of
+ (self, route)
+
+
Return list of children of given route, for generating index in Web Page
+
+
+
+
+
+
+
+
+
+
+ get_next
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ get_or_make_page_name
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ get_page_name
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ get_parent
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ get_parents
+ (self, context)
+
+
+
+
+
+
+
+
+
+
+
+ get_route
+ (self, doc=None)
+
+
+
+
+
+
+
+
+
+
+
+ get_route_context
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ has_children
+ (self, route)
+
+
+
+
+
+
+
+
+
+
+
+ make_page_name
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ on_trash
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ on_update
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ onload
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ set_parent_website_route
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ update_routes_of_descendants
+ (self, old_route=None)
+
+
+
+
+
+
+
+
+
+
+
+ validate
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ website_published
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.website.website_generator.make_route
+ (doc)
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/website/index.html b/frappe/docs/current/api/website/index.html
new file mode 100644
index 0000000000..2f8ab04e3b
--- /dev/null
+++ b/frappe/docs/current/api/website/index.html
@@ -0,0 +1,19 @@
+
+
+
+
+
+
Package Contents
+
+{index}
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/website/index.txt b/frappe/docs/current/api/website/index.txt
new file mode 100644
index 0000000000..45ac658638
--- /dev/null
+++ b/frappe/docs/current/api/website/index.txt
@@ -0,0 +1,8 @@
+frappe.website.context
+frappe.website
+frappe.website.render
+frappe.website.router
+frappe.website.statics
+frappe.website.template
+frappe.website.utils
+frappe.website.website_generator
\ No newline at end of file
diff --git a/frappe/docs/current/api/website/website_theme/frappe.website.website_theme.html b/frappe/docs/current/api/website/website_theme/frappe.website.website_theme.html
new file mode 100644
index 0000000000..23d923c534
--- /dev/null
+++ b/frappe/docs/current/api/website/website_theme/frappe.website.website_theme.html
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/website/website_theme/index.html b/frappe/docs/current/api/website/website_theme/index.html
new file mode 100644
index 0000000000..0decff8b71
--- /dev/null
+++ b/frappe/docs/current/api/website/website_theme/index.html
@@ -0,0 +1,19 @@
+
+
+
+
+
+
Package Contents
+
+{index}
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/website/website_theme/index.txt b/frappe/docs/current/api/website/website_theme/index.txt
new file mode 100644
index 0000000000..31655928c3
--- /dev/null
+++ b/frappe/docs/current/api/website/website_theme/index.txt
@@ -0,0 +1 @@
+frappe.website.website_theme
\ No newline at end of file
diff --git a/frappe/docs/current/api/website/website_theme/standard/frappe.website.website_theme.standard.html b/frappe/docs/current/api/website/website_theme/standard/frappe.website.website_theme.standard.html
new file mode 100644
index 0000000000..391b97cba7
--- /dev/null
+++ b/frappe/docs/current/api/website/website_theme/standard/frappe.website.website_theme.standard.html
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/website/website_theme/standard/index.html b/frappe/docs/current/api/website/website_theme/standard/index.html
new file mode 100644
index 0000000000..0edbd47deb
--- /dev/null
+++ b/frappe/docs/current/api/website/website_theme/standard/index.html
@@ -0,0 +1,19 @@
+
+
+
+
+
+
Package Contents
+
+{index}
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/website/website_theme/standard/index.txt b/frappe/docs/current/api/website/website_theme/standard/index.txt
new file mode 100644
index 0000000000..8a432687d6
--- /dev/null
+++ b/frappe/docs/current/api/website/website_theme/standard/index.txt
@@ -0,0 +1 @@
+frappe.website.website_theme.standard
\ No newline at end of file
diff --git a/frappe/docs/current/api/workflow/frappe.workflow.html b/frappe/docs/current/api/workflow/frappe.workflow.html
new file mode 100644
index 0000000000..9c42c758cb
--- /dev/null
+++ b/frappe/docs/current/api/workflow/frappe.workflow.html
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/workflow/index.html b/frappe/docs/current/api/workflow/index.html
new file mode 100644
index 0000000000..d8ba0fe810
--- /dev/null
+++ b/frappe/docs/current/api/workflow/index.html
@@ -0,0 +1,19 @@
+
+
+
+
+
+
Package Contents
+
+{index}
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/api/workflow/index.txt b/frappe/docs/current/api/workflow/index.txt
new file mode 100644
index 0000000000..dab7c26a6c
--- /dev/null
+++ b/frappe/docs/current/api/workflow/index.txt
@@ -0,0 +1 @@
+frappe.workflow
\ No newline at end of file
diff --git a/frappe/docs/current/index.html b/frappe/docs/current/index.html
new file mode 100644
index 0000000000..0ac6840f4f
--- /dev/null
+++ b/frappe/docs/current/index.html
@@ -0,0 +1,55 @@
+
+
+
+
+
+
+
+
+
+ App Name
+
+
+ frappe
+
+
+
+
+ Publisher
+
+
+ Frappe Technologies Pvt. Ltd.
+
+
+
+
+ Version
+
+
+ 6.16.3
+
+
+
+
+
Contents
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/core/async_task.html b/frappe/docs/current/models/core/async_task.html
new file mode 100644
index 0000000000..6598f2f332
--- /dev/null
+++ b/frappe/docs/current/models/core/async_task.html
@@ -0,0 +1,189 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
Table Name: tabAsync Task
+
+
+
+
+
Fields
+
+
+
+
+ Sr
+ Fieldname
+ Type
+ Label
+ Options
+
+
+
+
+
+ 1
+ status
+
+ Select
+
+ Status
+
+
+
+
+Queued
+Running
+Succeeded
+Failed
+
+
+
+
+
+ 2
+ task_name
+
+ Data
+
+ Task Name
+
+
+
+
+
+
+ 3
+ runtime
+
+ Data
+
+ Runtime
+
+
+
+
+
+
+ 4
+ result
+
+ Code
+
+ Result
+
+
+
+
+
+
+ 5
+ traceback
+
+ Code
+
+ Traceback
+
+
+
+
+
+
+ 6
+ section_break_6
+
+ Section Break
+
+
+
+
+
+
+
+
+ 7
+ reference_doctype
+
+ Link
+
+ Reference DocType
+
+
+
+
+
+
+
+DocType
+
+
+
+
+
+
+
+ 8
+ reference_name
+
+ Dynamic Link
+
+ Reference Doc
+
+
+
+ reference_doctype
+
+
+
+
+
+
+
+
+
Controller
+
frappe.core.doctype.async_task.async_task
+
+
+
+
+
+
+
+
Class AsyncTask
+
+
Inherits from frappe.model.document.Document
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/core/block_module.html b/frappe/docs/current/models/core/block_module.html
new file mode 100644
index 0000000000..9c57b9b7c3
--- /dev/null
+++ b/frappe/docs/current/models/core/block_module.html
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+
+
+
+
Child Table
+
+
+
Table Name: tabBlock Module
+
+
+
+
+
Fields
+
+
+
+
+ Sr
+ Fieldname
+ Type
+ Label
+ Options
+
+
+
+
+
+ 1
+ module
+
+ Data
+
+ Module
+
+
+
+
+
+
+
+
+
+
+
+
Child Table Of
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/core/comment.html b/frappe/docs/current/models/core/comment.html
new file mode 100644
index 0000000000..96eec2e578
--- /dev/null
+++ b/frappe/docs/current/models/core/comment.html
@@ -0,0 +1,404 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
Table Name: tabComment
+
+
+
+
+
Fields
+
+
+
+
+ Sr
+ Fieldname
+ Type
+ Label
+ Options
+
+
+
+
+
+ 1
+ comment
+
+ Text
+
+ Comment
+
+
+
+
+
+
+ 2
+ comment_type
+
+ Data
+
+ Comment Type
+
+
+
+ Email
+Chat
+Phone
+SMS
+Created
+Submitted
+Cancelled
+Assigned
+Assignment Completed
+Comment
+Workflow
+Label
+Attachment
+Attachment Removed
+
+
+
+
+ 3
+ comment_by
+
+ Data
+
+ Comment By
+
+
+
+
+
+
+ 4
+ comment_by_fullname
+
+ Data
+
+ Comment By Fullname
+
+
+
+
+
+
+ 5
+ comment_date
+
+ Date
+
+ Comment Date
+
+
+
+
+
+
+ 6
+ comment_time
+
+ Data
+
+ Comment Time
+
+
+
+
+
+
+ 7
+ comment_doctype
+
+ Data
+
+ Comment Doctype
+
+
+
+
+
+
+ 8
+ comment_docname
+
+ Data
+
+ Comment Docname
+
+
+
+
+
+
+ 9
+ post_topic
+
+ Data
+
+ Post Topic
+
+
+
+
+
+
+ 10
+ unsubscribed
+
+ Check
+
+ Unsubscribed
+
+
+
+
+
+
+ 11
+ reference_doctype
+
+ Link
+
+ Reference DocType
+
+
+
+
+
+
+
+DocType
+
+
+
+
+
+
+
+ 12
+ reference_name
+
+ Dynamic Link
+
+ Reference Name
+
+ Reference DocType and Reference Name are used to render a comment as a link (href) to a Doc.
+
+
+ reference_doctype
+
+
+
+
+
+
+
+
+
Controller
+
frappe.core.doctype.comment.comment
+
+
+
+
+
+
+
+
Class Comment
+
+
Inherits from frappe.model.document.Document
+
+
Comments are added to Documents via forms or views like blogs etc.
+
+
+
+
+
+
+
+
+
+ after_insert
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ get_comments_from_parent
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ get_feed
+ (self)
+
+
Returns feed HTML from Comment.
+
+
+
+
+
+
+
+
+
+
+ notify_mentions
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ on_trash
+ (self)
+
+
Removes from _comments in parent Document
+
+
+
+
+
+
+
+
+
+
+ on_update
+ (self)
+
+
Updates _comments property in parent Document.
+
+
+
+
+
+
+
+
+
+
+ update_comment_in_doc
+ (self)
+
+
Updates _comments (JSON) property in parent Document.
+Creates a column _comments if property does not exist.
+
+
_comments format
+
+
{
+ "comment": [String],
+ "by": [user],
+ "name": [Comment Document name]
+}
+
+
+
+
+
+
+
+
+
+
+
+ update_comments_in_parent
+ (self, _comments)
+
+
Updates _comments property in parent Document with given dict.
+
+
Parameters:
+
+
+_comments - Dict of comments.
+
+
+
+
+
+
+
+
+
+
+
+ validate
+ (self)
+
+
Raise exception for more than 50 comments.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.core.doctype.comment.comment.on_doctype_update
+ ()
+
+
Add index to tabComment (comment_doctype, comment_name)
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/core/communication.html b/frappe/docs/current/models/core/communication.html
new file mode 100644
index 0000000000..a754c28889
--- /dev/null
+++ b/frappe/docs/current/models/core/communication.html
@@ -0,0 +1,786 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
Table Name: tabCommunication
+
+
+Keep a track of all communications
+
+
Fields
+
+
+
+
+ Sr
+ Fieldname
+ Type
+ Label
+ Options
+
+
+
+
+
+ 1
+ naming_series
+
+ Select
+
+ Series
+
+
+
+ COMM-
+
+
+
+
+ 2
+ communication_medium
+
+ Select
+
+ Communication Medium
+
+
+
+
+Chat
+Phone
+Email
+SMS
+Visit
+Other
+
+
+
+
+ 3
+ recipients
+
+ Data
+
+ Recipients
+
+
+
+
+
+
+ 4
+ cc
+
+ Data
+
+ CC
+
+
+
+
+
+
+ 5
+ phone_no
+
+ Data
+
+ Phone No.
+
+
+
+
+
+
+ 6
+ column_break_5
+
+ Column Break
+
+
+
+
+
+
+
+
+ 7
+ status
+
+ Select
+
+ Status
+
+
+
+ Open
+Replied
+Closed
+Linked
+
+
+
+
+ 8
+ sent_or_received
+
+ Select
+
+ Sent or Received
+
+
+
+ Sent
+Received
+
+
+
+
+ 9
+ delivery_status
+
+ Select
+
+ Delivery Status
+
+ Integrations can use this field to set email delivery status
+
+
+
+Sent
+Bounced
+Opened
+Marked As Spam
+Rejected
+Delayed
+Soft-Bounced
+Clicked
+Recipient Unsubscribed
+
+
+
+
+ 10
+ section_break_10
+
+ Section Break
+
+
+
+
+
+
+
+
+ 11
+ subject
+
+ Data
+
+ Subject
+
+
+
+
+
+
+ 12
+ section_break_8
+
+ Section Break
+
+
+
+
+
+
+
+
+ 13
+ content
+
+ Text Editor
+
+ Content
+
+
+
+
+
+
+ 14
+ additional_info
+
+ Section Break
+
+ More Information
+
+
+
+
+
+
+ 15
+ sender
+
+ Data
+
+ Sender
+
+
+
+
+
+
+ 16
+ sender_full_name
+
+ Data
+
+ Sender Full Name
+
+
+
+
+
+
+ 17
+ communication_date
+
+ Datetime
+
+ Date
+
+
+
+
+
+
+ 18
+ column_break_14
+
+ Column Break
+
+
+
+
+
+
+
+
+ 19
+ reference_doctype
+
+ Link
+
+ Reference DocType
+
+
+
+
+
+
+
+DocType
+
+
+
+
+
+
+
+ 20
+ reference_name
+
+ Dynamic Link
+
+ Reference Name
+
+
+
+ reference_doctype
+
+
+
+
+ 21
+ in_reply_to
+
+ Link
+
+ In Reply To
+
+
+
+
+
+
+
+Communication
+
+
+
+
+
+
+
+ 22
+ email_account
+
+ Link
+
+ Email Account
+
+
+
+
+
+
+
+Email Account
+
+
+
+
+
+
+
+ 23
+ user
+
+ Link
+
+ User
+
+
+
+
+
+
+
+User
+
+
+
+
+
+
+
+ 24
+ unread_notification_sent
+
+ Check
+
+ Unread Notification Sent
+
+
+
+
+
+
+ 25
+ _user_tags
+
+ Data
+
+ User Tags
+
+
+
+
+
+
+
+
+
+
+
Controller
+
frappe.core.doctype.communication.communication
+
+
+
+
+
+
+
+
Class Communication
+
+
Inherits from frappe.model.document.Document
+
+
+
+
+
+
+
+
+
+
+ _notify
+ (self, print_html=None, print_format=None, attachments=None, recipients=None, cc=None)
+
+
+
+
+
+
+
+
+
+
+
+ after_insert
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ filter_email_list
+ (self, email_list, exclude, is_cc=False)
+
+
+
+
+
+
+
+
+
+
+
+ get_assignees
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ get_attach_link
+ (self, print_format)
+
+
Returns public link for the attachment via templates/emails/print_link.html.
+
+
+
+
+
+
+
+
+
+
+ get_cc
+ (self, recipients=None, fetched_from_email_account=False)
+
+
Build a list of email addresses for CC
+
+
+
+
+
+
+
+
+
+
+ get_owner_email
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ get_parent_doc
+ (self)
+
+
Returns document of reference_doctype, reference_doctype
+
+
+
+
+
+
+
+
+
+
+ get_recipients
+ (self, fetched_from_email_account=False)
+
+
Build a list of email addresses for To
+
+
+
+
+
+
+
+
+
+
+ get_recipients_and_cc
+ (self, recipients, cc, fetched_from_email_account=False)
+
+
+
+
+
+
+
+
+
+
+
+ get_starrers
+ (self)
+
+
Return list of users who have starred this document.
+
+
+
+
+
+
+
+
+
+
+ notify
+ (self, print_html=None, print_format=None, attachments=None, recipients=None, cc=None, fetched_from_email_account=False)
+
+
Calls a delayed celery task 'sendmail' that enqueus email in Bulk Email queue
+
+
Parameters:
+
+
+print_html - Send given value as HTML attachment
+print_format - Attach print format of parent document
+attachments - A list of filenames that should be attached when sending this email
+recipients - Email recipients
+cc - Send email as CC to
+fetched_from_email_account - True when pulling email, the notification shouldn't go to the main recipient
+
+
+
+
+
+
+
+
+
+
+
+ on_update
+ (self)
+
+
Update parent status as Open or Replied.
+
+
+
+
+
+
+
+
+
+
+ prepare_to_notify
+ (self, print_html=None, print_format=None, attachments=None)
+
+
Prepare to make multipart MIME Email
+
+
Parameters:
+
+
+print_html - Send given value as HTML attachment.
+print_format - Attach print format of parent document.
+
+
+
+
+
+
+
+
+
+
+
+ send
+ (self, print_html=None, print_format=None, attachments=None, send_me_a_copy=False, recipients=None)
+
+
Send communication via Email.
+
+
Parameters:
+
+
+print_html - Send given value as HTML attachment.
+print_format - Attach print format of parent document.
+
+
+
+
+
+
+
+
+
+
+
+ set_incoming_outgoing_accounts
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ update_parent
+ (self)
+
+
Update status of parent document based on who is replying.
+
+
+
+
+
+
+
+
+
+
+ validate
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.core.doctype.communication.communication.make
+
+
+
+
+ frappe.core.doctype.communication.communication.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.
+
+
Parameters:
+
+
+doctype - Reference DocType.
+name - Reference Document name.
+content - Communication body.
+subject - Communication subject.
+sent_or_received - Sent or Received (default Sent ).
+sender - Communcation sender (default current user).
+recipients - Communication recipients as list.
+communication_medium - Medium of communication (default Email ).
+send_mail - Send via email (default False ).
+print_html - HTML Print format to be sent as attachment.
+print_format - Print Format name of parent document to be sent as attachment.
+attachments - List of attachments as list of files or JSON string.
+send_me_a_copy - Send a copy to the sender (default False ).
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.core.doctype.communication.communication.on_doctype_update
+ ()
+
+
Add index in tabCommunication for (reference_doctype, reference_name)
+
+
+
+
+
+
+
+
+
Linked In:
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/core/defaultvalue.html b/frappe/docs/current/models/core/defaultvalue.html
new file mode 100644
index 0000000000..5f0b4562cd
--- /dev/null
+++ b/frappe/docs/current/models/core/defaultvalue.html
@@ -0,0 +1,87 @@
+
+
+
+
+
+
+
+
+
+
Child Table
+
+
+
Table Name: tabDefaultValue
+
+
+
+
+
Fields
+
+
+
+
+ Sr
+ Fieldname
+ Type
+ Label
+ Options
+
+
+
+
+
+ 1
+ defkey
+
+ Data
+
+ Key
+
+
+
+
+
+
+ 2
+ defvalue
+
+ Text
+
+ Value
+
+
+
+
+
+
+
+
+
+
+
+
Child Table Of
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/core/docfield.html b/frappe/docs/current/models/core/docfield.html
new file mode 100644
index 0000000000..b8ea49bf99
--- /dev/null
+++ b/frappe/docs/current/models/core/docfield.html
@@ -0,0 +1,553 @@
+
+
+
+
+
+
+
+
+
+
Child Table
+
+
+
Table Name: tabDocField
+
+
+
+
+
Fields
+
+
+
+
+ Sr
+ Fieldname
+ Type
+ Label
+ Options
+
+
+
+
+
+ 1
+ label_and_type
+
+ Section Break
+
+
+
+
+
+
+
+
+ 2
+ label
+
+ Data
+
+ Label
+
+
+
+
+
+
+ 3
+ fieldtype
+
+ Select
+
+ Type
+
+
+
+ Attach
+Attach Image
+Button
+Check
+Code
+Column Break
+Currency
+Data
+Date
+Datetime
+Dynamic Link
+Float
+Fold
+Heading
+HTML
+Image
+Int
+Link
+Long Text
+Password
+Percent
+Read Only
+Section Break
+Select
+Small Text
+Table
+Text
+Text Editor
+Time
+
+
+
+
+ 4
+ fieldname
+
+ Data
+
+ Name
+
+
+
+
+
+
+ 5
+ reqd
+
+ Check
+
+ Mandatory
+
+
+
+
+
+
+ 6
+ precision
+
+ Select
+
+ Precision
+
+ Set non-standard precision for a Float or Currency field
+
+
+
+1
+2
+3
+4
+5
+6
+7
+8
+9
+
+
+
+
+ 7
+ length
+
+ Int
+
+ Length
+
+
+
+
+
+
+ 8
+ search_index
+
+ Check
+
+ Index
+
+
+
+
+
+
+ 9
+ in_list_view
+
+ Check
+
+ In List View
+
+
+
+
+
+
+ 10
+ bold
+
+ Check
+
+ Bold
+
+
+
+
+
+
+ 11
+ collapsible
+
+ Check
+
+ Collapsible
+
+
+
+
+
+
+ 12
+ collapsible_depends_on
+
+ Small Text
+
+ Collapsible Depends On
+
+
+
+
+
+
+ 13
+ column_break_6
+
+ Column Break
+
+
+
+
+
+
+
+
+ 14
+ options
+
+ Text
+
+ Options
+
+ For Links, enter the DocType as range.
+For Select, enter list of Options, each on a new line.
+
+
+
+
+
+ 15
+ default
+
+ Small Text
+
+ Default
+
+
+
+
+
+
+ 16
+ permissions
+
+ Section Break
+
+ Permissions
+
+
+
+
+
+
+ 17
+ depends_on
+
+ Small Text
+
+ Depends On
+
+
+
+
+
+
+ 18
+ hidden
+
+ Check
+
+ Hidden
+
+
+
+
+
+
+ 19
+ read_only
+
+ Check
+
+ Read Only
+
+
+
+
+
+
+ 20
+ unique
+
+ Check
+
+ Unique
+
+
+
+
+
+
+ 21
+ set_only_once
+
+ Check
+
+ Set Only Once
+
+ Do not allow user to change after set the first time
+
+
+
+
+
+ 22
+ column_break_13
+
+ Column Break
+
+
+
+
+
+
+
+
+ 23
+ permlevel
+
+ Int
+
+ Perm Level
+
+
+
+
+
+
+ 24
+ ignore_user_permissions
+
+ Check
+
+ Ignore User Permissions
+
+ User permissions should not apply for this Link
+
+
+
+
+
+ 25
+ allow_on_submit
+
+ Check
+
+ Allow on Submit
+
+
+
+
+
+
+ 26
+ report_hide
+
+ Check
+
+ Report Hide
+
+
+
+
+
+
+ 27
+ display
+
+ Section Break
+
+ Display
+
+
+
+
+
+
+ 28
+ in_filter
+
+ Check
+
+ In Filter
+
+
+
+
+
+
+ 29
+ no_copy
+
+ Check
+
+ No Copy
+
+
+
+
+
+
+ 30
+ print_hide
+
+ Check
+
+ Print Hide
+
+
+
+
+
+
+ 31
+ print_hide_if_no_value
+
+ Check
+
+ Print Hide If No Value
+
+
+
+
+
+
+ 32
+ print_width
+
+ Data
+
+ Print Width
+
+
+
+
+
+
+ 33
+ width
+
+ Data
+
+ Width
+
+
+
+
+
+
+ 34
+ column_break_22
+
+ Column Break
+
+
+
+
+
+
+
+
+ 35
+ description
+
+ Small Text
+
+ Description
+
+
+
+
+
+
+ 36
+ oldfieldname
+
+ Data
+
+
+
+
+
+
+
+
+ 37
+ oldfieldtype
+
+ Data
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Child Table Of
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/core/docperm.html b/frappe/docs/current/models/core/docperm.html
new file mode 100644
index 0000000000..37b112900b
--- /dev/null
+++ b/frappe/docs/current/models/core/docperm.html
@@ -0,0 +1,376 @@
+
+
+
+
+
+
+
+
+
+
Child Table
+
+
+
Table Name: tabDocPerm
+
+
+
+
+
Fields
+
+
+
+
+ Sr
+ Fieldname
+ Type
+ Label
+ Options
+
+
+
+
+
+ 1
+ role_and_level
+
+ Section Break
+
+ Role and Level
+
+
+
+
+
+
+ 2
+ role
+
+ Link
+
+ Role
+
+
+
+
+
+
+
+Role
+
+
+
+
+
+
+
+ 3
+ apply_user_permissions
+
+ Check
+
+ Apply User Permissions
+
+ Filter records based on User Permissions defined for a user
+
+
+
+
+
+ 4
+ if_owner
+
+ Check
+
+ If user is the owner
+
+ Apply this rule if the User is the Owner
+
+
+
+
+
+ 5
+ column_break_2
+
+ Column Break
+
+
+
+
+
+
+
+
+ 6
+ permlevel
+
+ Int
+
+ Level
+
+
+
+
+
+
+ 7
+ user_permission_doctypes
+
+ Text
+
+ User Permission DocTypes
+
+ JSON list of DocTypes used to apply User Permissions. If empty, all linked DocTypes will be used to apply User Permissions.
+
+
+
+
+
+ 8
+ section_break_4
+
+ Section Break
+
+ Permissions
+
+
+
+
+
+
+ 9
+ read
+
+ Check
+
+ Read
+
+
+
+
+
+
+ 10
+ write
+
+ Check
+
+ Write
+
+
+
+
+
+
+ 11
+ create
+
+ Check
+
+ Create
+
+
+
+
+
+
+ 12
+ delete
+
+ Check
+
+ Delete
+
+
+
+
+
+
+ 13
+ column_break_8
+
+ Column Break
+
+
+
+
+
+
+
+
+ 14
+ submit
+
+ Check
+
+ Submit
+
+
+
+
+
+
+ 15
+ cancel
+
+ Check
+
+ Cancel
+
+
+
+
+
+
+ 16
+ amend
+
+ Check
+
+ Amend
+
+
+
+
+
+
+ 17
+ additional_permissions
+
+ Section Break
+
+ Additional Permissions
+
+
+
+
+
+
+ 18
+ report
+
+ Check
+
+ Report
+
+
+
+
+
+
+ 19
+ export
+
+ Check
+
+ Export
+
+
+
+
+
+
+ 20
+ import
+
+ Check
+
+ Import
+
+
+
+
+
+
+ 21
+ set_user_permissions
+
+ Check
+
+ Set User Permissions
+
+ This role update User Permissions for a user
+
+
+
+
+
+ 22
+ column_break_19
+
+ Column Break
+
+
+
+
+
+
+
+
+ 23
+ share
+
+ Check
+
+ Share
+
+
+
+
+
+
+ 24
+ print
+
+ Check
+
+ Print
+
+
+
+
+
+
+ 25
+ email
+
+ Check
+
+ Email
+
+
+
+
+
+
+
+
+
+
+
+
Child Table Of
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/core/docshare.html b/frappe/docs/current/models/core/docshare.html
new file mode 100644
index 0000000000..1f5b44c53a
--- /dev/null
+++ b/frappe/docs/current/models/core/docshare.html
@@ -0,0 +1,293 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
Table Name: tabDocShare
+
+
+Internal record of document shares
+
+
Fields
+
+
+
+
+ Sr
+ Fieldname
+ Type
+ Label
+ Options
+
+
+
+
+
+ 1
+ user
+
+ Link
+
+ User
+
+
+
+
+
+
+
+User
+
+
+
+
+
+
+
+ 2
+ share_doctype
+
+ Link
+
+ Document Type
+
+
+
+
+
+
+
+DocType
+
+
+
+
+
+
+
+ 3
+ share_name
+
+ Dynamic Link
+
+ Document Name
+
+
+
+ share_doctype
+
+
+
+
+ 4
+ read
+
+ Check
+
+ Read
+
+
+
+
+
+
+ 5
+ write
+
+ Check
+
+ Write
+
+
+
+
+
+
+ 6
+ share
+
+ Check
+
+ Share
+
+
+
+
+
+
+ 7
+ everyone
+
+ Check
+
+ Everyone
+
+
+
+
+
+
+
+
+
+
+
Controller
+
frappe.core.doctype.docshare.docshare
+
+
+
+
+
+
+
+
Class DocShare
+
+
Inherits from frappe.model.document.Document
+
+
+
+
+
+
+
+
+
+
+ after_insert
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ cascade_permissions_downwards
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ check_share_permission
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ get_doc
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ on_trash
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ validate
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ validate_user
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.core.doctype.docshare.docshare.on_doctype_update
+ ()
+
+
Add index in tabDocShare for (user, share_doctype)
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/core/error_snapshot.html b/frappe/docs/current/models/core/error_snapshot.html
new file mode 100644
index 0000000000..294921e97b
--- /dev/null
+++ b/frappe/docs/current/models/core/error_snapshot.html
@@ -0,0 +1,247 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
Table Name: tabError Snapshot
+
+
+
+
+
Fields
+
+
+
+
+ Sr
+ Fieldname
+ Type
+ Label
+ Options
+
+
+
+
+
+ 1
+ view
+
+ HTML
+
+ Snapshot View
+
+
+
+
+
+
+ 2
+ seen
+
+ Check
+
+ Seen
+
+
+
+
+
+
+ 3
+ evalue
+
+ Small Text
+
+ Friendly Title
+
+
+
+
+
+
+ 4
+ timestamp
+
+ Datetime
+
+ Timestamp
+
+
+
+
+
+
+ 5
+ relapses
+
+ Int
+
+ Relapses
+
+
+
+
+
+
+ 6
+ etype
+
+ Data
+
+ Exception Type
+
+
+
+
+
+
+ 7
+ traceback
+
+ Small Text
+
+ Traceback
+
+
+
+
+
+
+ 8
+ parent_error_snapshot
+
+ Data
+
+ Parent Error Snapshot
+
+
+
+
+
+
+ 9
+ pyver
+
+ Small Text
+
+ Pyver
+
+
+
+
+
+
+ 10
+ exception
+
+ Small Text
+
+ Exception
+
+
+
+
+
+
+ 11
+ locals
+
+ Text
+
+ Locals
+
+
+
+
+
+
+ 12
+ frames
+
+ Text
+
+ Frames
+
+
+
+
+
+
+
+
+
+
+
Controller
+
frappe.core.doctype.error_snapshot.error_snapshot
+
+
+
+
+
+
+
+
Class ErrorSnapshot
+
+
Inherits from frappe.model.document.Document
+
+
+
+
+
+
+
+
+
+
+ onload
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ validate
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/core/file.html b/frappe/docs/current/models/core/file.html
new file mode 100644
index 0000000000..529eda44c8
--- /dev/null
+++ b/frappe/docs/current/models/core/file.html
@@ -0,0 +1,849 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
Table Name: tabFile
+
+
+
+
+
Fields
+
+
+
+
+ Sr
+ Fieldname
+ Type
+ Label
+ Options
+
+
+
+
+
+ 1
+ file_name
+
+ Data
+
+ File Name
+
+
+
+
+
+
+ 2
+ is_private
+
+ Check
+
+ Is Private
+
+
+
+
+
+
+ 3
+ preview
+
+ Section Break
+
+ Preview
+
+
+
+
+
+
+ 4
+ preview_html
+
+ HTML
+
+ Preview HTML
+
+
+
+
+
+
+ 5
+ section_break_5
+
+ Section Break
+
+
+
+
+
+
+
+
+ 6
+ is_home_folder
+
+ Check
+
+ Is Home Folder
+
+
+
+
+
+
+ 7
+ is_attachments_folder
+
+ Check
+
+ Is Attachments Folder
+
+
+
+
+
+
+ 8
+ file_size
+
+ Int
+
+ File Size
+
+
+
+
+
+
+ 9
+ column_break_5
+
+ Column Break
+
+
+
+
+
+
+
+
+ 10
+ file_url
+
+ Small Text
+
+ File URL
+
+
+
+
+
+
+ 11
+ thumbnail_url
+
+ Small Text
+
+ Thumbnail URL
+
+
+
+
+
+
+ 12
+ folder
+
+ Link
+
+ Folder
+
+
+
+
+
+
+
+File
+
+
+
+
+
+
+
+ 13
+ is_folder
+
+ Check
+
+ Is Folder
+
+
+
+
+
+
+ 14
+ section_break_8
+
+ Section Break
+
+
+
+
+
+
+
+
+ 15
+ attached_to_doctype
+
+ Link
+
+ Attached To DocType
+
+
+
+
+
+
+
+DocType
+
+
+
+
+
+
+
+ 16
+ column_break_10
+
+ Column Break
+
+
+
+
+
+
+
+
+ 17
+ attached_to_name
+
+ Data
+
+ Attached To Name
+
+
+
+
+
+
+ 18
+ content_hash
+
+ Data
+
+ Content Hash
+
+
+
+
+
+
+ 19
+ lft
+
+ Int
+
+ lft
+
+
+
+
+
+
+ 20
+ rgt
+
+ Int
+
+ rgt
+
+
+
+
+
+
+ 21
+ old_parent
+
+ Data
+
+ old_parent
+
+
+
+
+
+
+
+
+
+
+
Controller
+
frappe.core.doctype.file.file
+
+
+
+
+
+
+
+
Class File
+
+
Inherits from frappe.utils.nestedset.NestedSet
+
+
+
+
+
+
+
+
+
+
+ after_delete
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ after_insert
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ after_rename
+ (self, olddn, newdn, merge=False)
+
+
+
+
+
+
+
+
+
+
+
+ before_insert
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ check_folder_is_empty
+ (self)
+
+
Throw exception if folder is not empty
+
+
+
+
+
+
+
+
+
+
+ check_reference_doc_permission
+ (self)
+
+
Check if permission exists for reference document
+
+
+
+
+
+
+
+
+
+
+ delete_file
+ (self)
+
+
If file not attached to any other record, delete it
+
+
+
+
+
+
+
+
+
+
+ generate_content_hash
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ get_folder_size
+ (self, folder=None)
+
+
Returns folder size for current folder
+
+
+
+
+
+
+
+
+
+
+ get_name_based_on_parent_folder
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ get_successor
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ make_thumbnail
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ on_rollback
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ on_trash
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ set_folder_name
+ (self)
+
+
Make parent folders if not exists based on reference doctype and name
+
+
+
+
+
+
+
+
+
+
+ set_folder_size
+ (self)
+
+
Set folder size if folder
+
+
+
+
+
+
+
+
+
+
+ set_name
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ update_parent_folder_size
+ (self)
+
+
Update size of parent folder
+
+
+
+
+
+
+
+
+
+
+ validate
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ validate_duplicate_entry
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ validate_file
+ (self)
+
+
Validates existence of public file
+TODO: validate for private file
+
+
+
+
+
+
+
+
+
+
+ validate_folder
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+
+
Class FolderNotEmpty
+
+
Inherits from frappe.exceptions.ValidationError
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.core.doctype.file.file.check_file_permission
+ (file_url)
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.core.doctype.file.file.create_new_folder
+
+
+
+
+ frappe.core.doctype.file.file.create_new_folder
+ (file_name, folder)
+
+
create new folder under current parent folder
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.core.doctype.file.file.get_breadcrumbs
+
+
+
+
+ frappe.core.doctype.file.file.get_breadcrumbs
+ (folder)
+
+
returns name, file_name of parent folder
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.core.doctype.file.file.get_extension
+ (filename, extn, content)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.core.doctype.file.file.get_local_image
+ (file_url)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.core.doctype.file.file.get_web_image
+ (file_url)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.core.doctype.file.file.make_home_folder
+ ()
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.core.doctype.file.file.move_file
+
+
+
+
+ frappe.core.doctype.file.file.move_file
+ (file_list, new_parent, old_parent)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.core.doctype.file.file.on_doctype_update
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.core.doctype.file.file.setup_folder_path
+ (filename, new_parent)
+
+
+
+
+
+
+
+
+
+
Linked In:
+
+
+
+
+
+
+File
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/core/index.html b/frappe/docs/current/models/core/index.html
new file mode 100644
index 0000000000..d09bf76e79
--- /dev/null
+++ b/frappe/docs/current/models/core/index.html
@@ -0,0 +1,19 @@
+
+
+
+
+
+
DocTypes for core
+
+{index}
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/core/index.txt b/frappe/docs/current/models/core/index.txt
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/frappe/docs/current/models/core/module_def.html b/frappe/docs/current/models/core/module_def.html
new file mode 100644
index 0000000000..9c5251120b
--- /dev/null
+++ b/frappe/docs/current/models/core/module_def.html
@@ -0,0 +1,183 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
Table Name: tabModule Def
+
+
+
+
+
Fields
+
+
+
+
+ Sr
+ Fieldname
+ Type
+ Label
+ Options
+
+
+
+
+
+ 1
+ module_name
+
+ Data
+
+ Module Name
+
+
+
+
+
+
+ 2
+ app_name
+
+ Data
+
+ App Name
+
+
+
+
+
+
+
+
+
+
+
Controller
+
frappe.core.doctype.module_def.module_def
+
+
+
+
+
+
+
+
Class ModuleDef
+
+
Inherits from frappe.model.document.Document
+
+
+
+
+
+
+
+
+
+
+ add_to_modules_txt
+ (self)
+
+
Adds to [app]/modules.txt
+
+
+
+
+
+
+
+
+
+
+ create_modules_folder
+ (self)
+
+
Creates a folder [app]/[module] and adds __init__.py
+
+
+
+
+
+
+
+
+
+
+ on_update
+ (self)
+
+
If in developer_mode, create folder for module and
+add in modules.txt of app if missing.
+
+
+
+
+
+
+
+
+
+
+
+
+
Linked In:
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/core/page.html b/frappe/docs/current/models/core/page.html
new file mode 100644
index 0000000000..a2dbaba2f9
--- /dev/null
+++ b/frappe/docs/current/models/core/page.html
@@ -0,0 +1,292 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
Table Name: tabPage
+
+
+
+
+
Fields
+
+
+
+
+ Sr
+ Fieldname
+ Type
+ Label
+ Options
+
+
+
+
+
+ 1
+ page_html
+
+ Section Break
+
+ Page HTML
+
+
+
+
+
+
+ 2
+ page_name
+
+ Data
+
+ Page Name
+
+
+
+
+
+
+ 3
+ title
+
+ Data
+
+ Title
+
+
+
+
+
+
+ 4
+ icon
+
+ Data
+
+ icon
+
+
+
+
+
+
+ 5
+ column_break0
+
+ Column Break
+
+
+
+
+
+
+
+
+ 6
+ module
+
+ Link
+
+ Module
+
+
+
+
+
+
+
+Module Def
+
+
+
+
+
+
+
+ 7
+ standard
+
+ Select
+
+ Standard
+
+
+
+
+Yes
+No
+
+
+
+
+ 8
+ section_break0
+
+ Section Break
+
+
+
+
+
+
+
+
+ 9
+ roles
+
+ Table
+
+ Roles
+
+
+
+
+
+
+
+Page Role
+
+
+
+
+
+
+
+
+
+
+
+
Controller
+
frappe.core.doctype.page.page
+
+
+
+
+
+
+
+
Class Page
+
+
Inherits from frappe.model.document.Document
+
+
+
+
+
+
+
+
+
+
+ as_dict
+ (self, no_nulls=False)
+
+
+
+
+
+
+
+
+
+
+
+ autoname
+ (self)
+
+
Creates a url friendly name for this page.
+Will restrict the name to 30 characters, if there exists a similar name,
+it will add name-1, name-2 etc.
+
+
+
+
+
+
+
+
+
+
+ is_permitted
+ (self)
+
+
Returns true if Page Role is not set or the user is allowed.
+
+
+
+
+
+
+
+
+
+
+ load_assets
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ on_update
+ (self)
+
+
Writes the .txt for this page and if write_content is checked,
+it will write out a .html file
+
+
+
+
+
+
+
+
+
+
+ validate
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/core/page_role.html b/frappe/docs/current/models/core/page_role.html
new file mode 100644
index 0000000000..bbf9c55f37
--- /dev/null
+++ b/frappe/docs/current/models/core/page_role.html
@@ -0,0 +1,84 @@
+
+
+
+
+
+
+
+
+
+
Child Table
+
+
+
Table Name: tabPage Role
+
+
+
+
+
Fields
+
+
+
+
+ Sr
+ Fieldname
+ Type
+ Label
+ Options
+
+
+
+
+
+ 1
+ role
+
+ Link
+
+ Role
+
+
+
+
+
+
+
+Role
+
+
+
+
+
+
+
+
+
+
+
+
+
Child Table Of
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/core/patch_log.html b/frappe/docs/current/models/core/patch_log.html
new file mode 100644
index 0000000000..3785e4577a
--- /dev/null
+++ b/frappe/docs/current/models/core/patch_log.html
@@ -0,0 +1,87 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
Table Name: tabPatch Log
+
+
+List of patches executed
+
+
Fields
+
+
+
+
+ Sr
+ Fieldname
+ Type
+ Label
+ Options
+
+
+
+
+
+ 1
+ patch
+
+ Small Text
+
+ Patch
+
+
+
+
+
+
+
+
+
+
+
Controller
+
frappe.core.doctype.patch_log.patch_log
+
+
+
+
+
+
+
+
Class PatchLog
+
+
Inherits from frappe.model.document.Document
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/core/report.html b/frappe/docs/current/models/core/report.html
new file mode 100644
index 0000000000..98c3a19b8d
--- /dev/null
+++ b/frappe/docs/current/models/core/report.html
@@ -0,0 +1,327 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
Table Name: tabReport
+
+
+
+
+
Fields
+
+
+
+
+ Sr
+ Fieldname
+ Type
+ Label
+ Options
+
+
+
+
+
+ 1
+ report_name
+
+ Data
+
+ Report Name
+
+
+
+
+
+
+ 2
+ ref_doctype
+
+ Link
+
+ Ref DocType
+
+
+
+
+
+
+
+DocType
+
+
+
+
+
+
+
+ 3
+ is_standard
+
+ Select
+
+ Is Standard
+
+
+
+ No
+Yes
+
+
+
+
+ 4
+ module
+
+ Link
+
+ Module
+
+
+
+
+
+
+
+Module Def
+
+
+
+
+
+
+
+ 5
+ add_total_row
+
+ Check
+
+ Add Total Row
+
+
+
+
+
+
+ 6
+ column_break_4
+
+ Column Break
+
+
+
+
+
+
+
+
+ 7
+ report_type
+
+ Select
+
+ Report Type
+
+
+
+ Report Builder
+Query Report
+Script Report
+
+
+
+
+ 8
+ disabled
+
+ Check
+
+ Disabled
+
+
+
+
+
+
+ 9
+ apply_user_permissions
+
+ Check
+
+ Apply User Permissions
+
+
+
+
+
+
+ 10
+ section_break_6
+
+ Section Break
+
+
+
+
+
+
+
+
+ 11
+ query
+
+ Code
+
+ Query
+
+
+
+
+
+
+ 12
+ javascript
+
+ Code
+
+ Javascript
+
+ JavaScript Format: frappe.query_reports['REPORTNAME'] = {}
+
+
+
+
+
+ 13
+ json
+
+ Text
+
+ JSON
+
+
+
+
+
+
+
+
+
+
+
Controller
+
frappe.core.doctype.report.report
+
+
+
+
+
+
+
+
Class Report
+
+
Inherits from frappe.model.document.Document
+
+
+
+
+
+
+
+
+
+
+ create_report_py
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ export_doc
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ on_update
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ toggle_disable
+ (self, disable)
+
+
+
+
+
+
+
+
+
+
+
+ validate
+ (self)
+
+
only administrator can save standard report
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/core/role.html b/frappe/docs/current/models/core/role.html
new file mode 100644
index 0000000000..52adc61024
--- /dev/null
+++ b/frappe/docs/current/models/core/role.html
@@ -0,0 +1,175 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
Table Name: tabRole
+
+
+
+
+
Fields
+
+
+
+
+ Sr
+ Fieldname
+ Type
+ Label
+ Options
+
+
+
+
+
+ 1
+ role_name
+
+ Data
+
+ Role Name
+
+
+
+
+
+
+
+
+
+
+
Controller
+
frappe.core.doctype.role.role
+
+
+
+
+
+
+
+
Class Role
+
+
Inherits from frappe.model.document.Document
+
+
+
+
+
+
+
+
+
+
+ after_insert
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Linked In:
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/core/scheduler_log.html b/frappe/docs/current/models/core/scheduler_log.html
new file mode 100644
index 0000000000..1bb00ef704
--- /dev/null
+++ b/frappe/docs/current/models/core/scheduler_log.html
@@ -0,0 +1,141 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
Table Name: tabScheduler Log
+
+
+Log of Scheduler Errors
+
+
Fields
+
+
+
+
+ Sr
+ Fieldname
+ Type
+ Label
+ Options
+
+
+
+
+
+ 1
+ seen
+
+ Check
+
+ Seen
+
+
+
+
+
+
+ 2
+ method
+
+ Data
+
+ Method
+
+
+
+
+
+
+ 3
+ error
+
+ Text
+
+ Error
+
+
+
+
+
+
+
+
+
+
+
Controller
+
frappe.core.doctype.scheduler_log.scheduler_log
+
+
+
+
+
+
+
+
Class SchedulerLog
+
+
Inherits from frappe.model.document.Document
+
+
+
+
+
+
+
+
+
+
+ onload
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.core.doctype.scheduler_log.scheduler_log.set_old_logs_as_seen
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/core/system_settings.html b/frappe/docs/current/models/core/system_settings.html
new file mode 100644
index 0000000000..106f058406
--- /dev/null
+++ b/frappe/docs/current/models/core/system_settings.html
@@ -0,0 +1,391 @@
+
+
+
+
+
+
+
+
+
Single
+
+
+
+
+
+
+
Fields
+
+
+
+
+ Sr
+ Fieldname
+ Type
+ Label
+ Options
+
+
+
+
+
+ 1
+ localization
+
+ Section Break
+
+
+
+
+
+
+
+
+ 2
+ language
+
+ Select
+
+ Language
+
+
+
+ Loading...
+
+
+
+
+ 3
+ column_break_3
+
+ Column Break
+
+
+
+
+
+
+
+
+ 4
+ time_zone
+
+ Select
+
+ Time Zone
+
+
+
+
+
+
+ 5
+ date_and_number_format
+
+ Section Break
+
+
+
+
+
+
+
+
+ 6
+ date_format
+
+ Select
+
+ Date Format
+
+
+
+ yyyy-mm-dd
+dd-mm-yyyy
+dd/mm/yyyy
+dd.mm.yyyy
+mm/dd/yyyy
+mm-dd-yyyy
+
+
+
+
+ 7
+ column_break_7
+
+ Column Break
+
+
+
+
+
+
+
+
+ 8
+ number_format
+
+ Select
+
+ Number Format
+
+
+
+ #,###.##
+#.###,##
+# ###.##
+# ###,##
+#'###.##
+#, ###.##
+#,##,###.##
+#,###.###
+#.###
+#,###
+
+
+
+
+ 9
+ float_precision
+
+ Select
+
+ Float Precision
+
+
+
+
+2
+3
+4
+5
+6
+
+
+
+
+ 10
+ security
+
+ Section Break
+
+ Security
+
+
+
+
+
+
+ 11
+ session_expiry
+
+ Data
+
+ Session Expiry
+
+ Session Expiry in Hours e.g. 06:00
+
+
+
+
+
+ 12
+ session_expiry_mobile
+
+ Data
+
+ Session Expiry Mobile
+
+ In Hours
+
+
+
+
+
+ 13
+ column_break_13
+
+ Column Break
+
+
+
+
+
+
+
+
+ 14
+ enable_scheduler
+
+ Check
+
+ Enable Scheduled Jobs
+
+ Run scheduled jobs only if checked
+
+
+
+
+
+ 15
+ scheduler_last_event
+
+ Data
+
+ Scheduler Last Event
+
+
+
+
+
+
+ 16
+ ignore_user_permissions_if_missing
+
+ Check
+
+ Ignore User Permissions If Missing
+
+ eg. If Apply User Permissions is checked for Report DocType but no User Permissions are defined for Report for a User, then all Reports are shown to that User
+
+
+
+
+
+ 17
+ email
+
+ Section Break
+
+ EMail
+
+
+
+
+
+
+ 18
+ email_footer_address
+
+ Small Text
+
+ Email Footer Address
+
+ Your organization name and address for the email footer.
+
+
+
+
+
+ 19
+ column_break_18
+
+ Column Break
+
+
+
+
+
+
+
+
+ 20
+ disable_standard_email_footer
+
+ Check
+
+ Disable Standard Email Footer
+
+
+
+
+
+
+
+
+
+
+
Controller
+
frappe.core.doctype.system_settings.system_settings
+
+
+
+
+
+
+
+
Class SystemSettings
+
+
Inherits from frappe.model.document.Document
+
+
+
+
+
+
+
+
+
+
+ on_update
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ validate
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.core.doctype.system_settings.system_settings.load
+
+
+
+
+ frappe.core.doctype.system_settings.system_settings.load
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/core/user.html b/frappe/docs/current/models/core/user.html
new file mode 100644
index 0000000000..f51f81074d
--- /dev/null
+++ b/frappe/docs/current/models/core/user.html
@@ -0,0 +1,1628 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
Table Name: tabUser
+
+
+Represents a User in the system.
+
+
Fields
+
+
+
+
+ Sr
+ Fieldname
+ Type
+ Label
+ Options
+
+
+
+
+
+ 1
+ sb0_5
+
+ Section Break
+
+
+
+
+
+
+
+
+ 2
+ enabled
+
+ Check
+
+ Enabled
+
+
+
+
+
+
+ 3
+ section_break_3
+
+ Section Break
+
+
+
+
+
+
+
+
+ 4
+ email
+
+ Data
+
+ Email
+
+
+
+ Email
+
+
+
+
+ 5
+ first_name
+
+ Data
+
+ First Name
+
+
+
+
+
+
+ 6
+ middle_name
+
+ Data
+
+ Middle Name (Optional)
+
+
+
+
+
+
+ 7
+ last_name
+
+ Data
+
+ Last Name
+
+
+
+
+
+
+ 8
+ username
+
+ Data
+
+ Username
+
+
+
+
+
+
+ 9
+ send_welcome_email
+
+ Check
+
+ Send Welcome Email
+
+
+
+
+
+
+ 10
+ unsubscribed
+
+ Check
+
+ Unsubscribed
+
+
+
+
+
+
+ 11
+ column_break0
+
+ Column Break
+
+
+
+
+
+
+
+
+ 12
+ language
+
+ Select
+
+ Language
+
+
+
+ Loading...
+
+
+
+
+ 13
+ time_zone
+
+ Select
+
+ Timezone
+
+
+
+
+
+
+ 14
+ user_image
+
+ Attach Image
+
+ User Image
+
+ Get your globally recognized avatar from Gravatar.com
+
+
+
+
+
+ 15
+ short_bio
+
+ Section Break
+
+ More Information
+
+
+
+
+
+
+ 16
+ gender
+
+ Select
+
+ Gender
+
+
+
+
+Male
+Female
+Other
+
+
+
+
+ 17
+ birth_date
+
+ Date
+
+ Birth Date
+
+
+
+
+
+
+ 18
+ location
+
+ Data
+
+ Location
+
+
+
+
+
+
+ 19
+ column_break_22
+
+ Column Break
+
+
+
+
+
+
+
+
+ 20
+ bio
+
+ Small Text
+
+ Bio
+
+
+
+
+
+
+ 21
+ mute_sounds
+
+ Check
+
+ Mute Sounds
+
+
+
+
+
+
+ 22
+ change_password
+
+ Section Break
+
+ Change Password
+
+
+
+
+
+
+ 23
+ new_password
+
+ Password
+
+ Set New Password
+
+
+
+
+
+
+ 24
+ send_password_update_notification
+
+ Check
+
+ Send Password Update Notification
+
+
+
+
+
+
+ 25
+ reset_password_key
+
+ Data
+
+ Reset Password Key
+
+
+
+
+
+
+ 26
+ email_settings
+
+ Section Break
+
+ Email Settings
+
+
+
+
+
+
+ 27
+ thread_notify
+
+ Check
+
+ Send Notifications for Transactions I Follow
+
+
+
+
+
+
+ 28
+ email_signature
+
+ Small Text
+
+ Email Signature
+
+
+
+
+
+
+ 29
+ background
+
+ Section Break
+
+ Desktop Background
+
+
+
+
+
+
+ 30
+ background_image
+
+ Attach
+
+ Background Image
+
+
+
+
+
+
+ 31
+ background_style
+
+ Select
+
+ Background Style
+
+
+
+ Fill Screen
+Tile
+
+
+
+
+ 32
+ sb1
+
+ Section Break
+
+ Roles
+
+ Check / Uncheck roles assigned to the User. Click on the Role to find out what permissions that Role has.
+
+
+
+
+
+ 33
+ roles_html
+
+ HTML
+
+ Roles HTML
+
+
+
+
+
+
+ 34
+ user_roles
+
+ Table
+
+ Roles Assigned
+
+
+
+
+
+
+
+UserRole
+
+
+
+
+
+
+
+ 35
+ modules_access
+
+ Section Break
+
+ Modules Access
+
+ Uncheck modules to hide from user's desktop
+
+
+
+
+
+ 36
+ modules_html
+
+ HTML
+
+ Modules HTML
+
+
+
+
+
+
+ 37
+ block_modules
+
+ Table
+
+ Block Modules
+
+
+
+
+
+
+
+Block Module
+
+
+
+
+
+
+
+ 38
+ sb2
+
+ Section Break
+
+ Defaults
+
+ These values will be automatically updated in transactions and also will be useful to restrict permissions for this user on transactions containing these values.
+
+
+
+
+
+ 39
+ defaults
+
+ Table
+
+ User Defaults
+
+ Enter default value fields (keys) and values. If you add multiple values for a field, the first one will be picked. These defaults are also used to set "match" permission rules. To see list of fields, go to "Customize Form".
+
+
+
+
+
+
+DefaultValue
+
+
+
+
+
+
+
+ 40
+ sb3
+
+ Section Break
+
+ Security Settings
+
+
+
+
+
+
+ 41
+ user_type
+
+ Select
+
+ User Type
+
+ User Type "System User" can access Desktop. "Website User" can only be logged into the website and portal pages.
+
+
+ System User
+Website User
+
+
+
+
+ 42
+ login_after
+
+ Int
+
+ Login After
+
+ Allow user to login only after this hour (0-24)
+
+
+
+
+
+ 43
+ login_before
+
+ Int
+
+ Login Before
+
+ Allow user to login only before this hour (0-24)
+
+
+
+
+
+ 44
+ restrict_ip
+
+ Data
+
+ Restrict IP
+
+ Restrict user from this IP address only. Multiple IP addresses can be added by separating with commas. Also accepts partial IP addresses like (111.111.111)
+
+
+
+
+
+ 45
+ column_break1
+
+ Column Break
+
+
+
+
+
+
+
+
+ 46
+ last_login
+
+ Read Only
+
+ Last Login
+
+
+
+
+
+
+ 47
+ last_ip
+
+ Read Only
+
+ Last IP
+
+
+
+
+
+
+ 48
+ last_active
+
+ Datetime
+
+ Last Active
+
+
+
+
+
+
+ 49
+ last_known_versions
+
+ Text
+
+ Last Known Versions
+
+ Stores the JSON of last known versions of various installed apps. It is used to show release notes.
+
+
+
+
+
+ 50
+ third_party_authentication
+
+ Section Break
+
+ Third Party Authentication
+
+
+
+
+
+
+ 51
+ fb_username
+
+ Data
+
+ Facebook Username
+
+
+
+
+
+
+ 52
+ fb_userid
+
+ Data
+
+ Facebook User ID
+
+
+
+
+
+
+ 53
+ google_userid
+
+ Data
+
+ Google User ID
+
+
+
+
+
+
+ 54
+ column_break_49
+
+ Column Break
+
+
+
+
+
+
+
+
+ 55
+ github_userid
+
+ Data
+
+ Github User ID
+
+
+
+
+
+
+ 56
+ github_username
+
+ Data
+
+ Github Username
+
+
+
+
+
+
+
+
+
+
+
Controller
+
frappe.core.doctype.user.user
+
+
+
+
+
+
+
+
Class User
+
+
Inherits from frappe.model.document.Document
+
+
+
+
+
+
+
+
+
+
+ a_system_manager_should_exist
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ add_roles
+ (self)
+
+
Add roles to user and save
+
+
+
+
+
+
+
+
+
+
+ add_system_manager_role
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ after_rename
+ (self, olddn, newdn, merge=False)
+
+
+
+
+
+
+
+
+
+
+
+ append_roles
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ autoname
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ before_rename
+ (self, olddn, newdn, merge=False)
+
+
+
+
+
+
+
+
+
+
+
+ check_enable_disable
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ email_new_password
+ (self, new_password=None)
+
+
+
+
+
+
+
+
+
+
+
+ ensure_unique_roles
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ get_fullname
+ (self)
+
+
get firstname space last name
+
+
+
+
+
+
+
+
+
+
+ get_other_system_managers
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ on_trash
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ on_update
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ password_reset_mail
+ (self, link)
+
+
+
+
+
+
+
+
+
+
+
+ password_update_mail
+ (self, password)
+
+
+
+
+
+
+
+
+
+
+
+ remove_all_roles_for_guest
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ remove_roles
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ reset_password
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ send_login_mail
+ (self, subject, template, add_args)
+
+
send mail with login details
+
+
+
+
+
+
+
+
+
+
+ send_password_notifcation
+ (self, new_password)
+
+
+
+
+
+
+
+
+
+
+
+ send_welcome_mail_to_user
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ share_with_self
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ suggest_username
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ update_gravatar
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ username_exists
+ (self, username=None)
+
+
+
+
+
+
+
+
+
+
+
+ validate
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ validate_email_type
+ (self, email)
+
+
+
+
+
+
+
+
+
+
+
+ validate_rename
+ (self, olddn, newdn)
+
+
+
+
+
+
+
+
+
+
+
+ validate_share
+ (self, docshare)
+
+
+
+
+
+
+
+
+
+
+
+ validate_system_manager_user_type
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ validate_username
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.core.doctype.user.user.extract_mentions
+ (txt)
+
+
Find all instances of @username in the string.
+The mentions will be separated by non-word characters or may appear at the start of the string
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.core.doctype.user.user.get_active_users
+ ()
+
+
Returns No. of system users who logged in, in the last 3 days
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.core.doctype.user.user.get_active_website_users
+ ()
+
+
Returns No. of website users who logged in, in the last 3 days
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.core.doctype.user.user.get_all_roles
+
+
+
+
+ frappe.core.doctype.user.user.get_all_roles
+ (arg=None)
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.core.doctype.user.user.get_languages
+
+
+
+
+ frappe.core.doctype.user.user.get_languages
+ ()
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.core.doctype.user.user.get_perm_info
+
+
+
+
+ frappe.core.doctype.user.user.get_perm_info
+ (arg=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.core.doctype.user.user.get_permission_query_conditions
+ (user)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.core.doctype.user.user.get_system_users
+ (exclude_users=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.core.doctype.user.user.get_total_users
+ (exclude_users=None)
+
+
Returns total no. of system users
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.core.doctype.user.user.get_user_roles
+
+
+
+
+ frappe.core.doctype.user.user.get_user_roles
+ (arg=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.core.doctype.user.user.get_website_users
+ ()
+
+
Returns total no. of website users
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.core.doctype.user.user.has_permission
+ (doc, user)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.core.doctype.user.user.notifify_admin_access_to_system_manager
+ (login_manager=None)
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.core.doctype.user.user.reset_password
+
+
+
+
+ frappe.core.doctype.user.user.reset_password
+ (user)
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.core.doctype.user.user.sign_up
+
+
+
+
+ frappe.core.doctype.user.user.sign_up
+ (email, full_name)
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.core.doctype.user.user.update_password
+
+
+
+
+ frappe.core.doctype.user.user.update_password
+ (new_password, key=None, old_password=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.core.doctype.user.user.user_query
+ (doctype, txt, searchfield, start, page_len, filters)
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.core.doctype.user.user.verify_password
+
+
+
+
+ frappe.core.doctype.user.user.verify_password
+ (password)
+
+
+
+
+
+
+
+
+
+
Linked In:
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/core/userrole.html b/frappe/docs/current/models/core/userrole.html
new file mode 100644
index 0000000000..4d18ca8625
--- /dev/null
+++ b/frappe/docs/current/models/core/userrole.html
@@ -0,0 +1,84 @@
+
+
+
+
+
+
+
+
+
+
Child Table
+
+
+
Table Name: tabUserRole
+
+
+
+
+
Fields
+
+
+
+
+ Sr
+ Fieldname
+ Type
+ Label
+ Options
+
+
+
+
+
+ 1
+ role
+
+ Link
+
+ Role
+
+
+
+
+
+
+
+Role
+
+
+
+
+
+
+
+
+
+
+
+
+
Child Table Of
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/core/version.html b/frappe/docs/current/models/core/version.html
new file mode 100644
index 0000000000..23d70fa1a2
--- /dev/null
+++ b/frappe/docs/current/models/core/version.html
@@ -0,0 +1,138 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
Table Name: tabVersion
+
+
+
+
+
Fields
+
+
+
+
+ Sr
+ Fieldname
+ Type
+ Label
+ Options
+
+
+
+
+
+ 1
+ ref_doctype
+
+ Link
+
+ Ref DocType
+
+
+
+
+
+
+
+DocType
+
+
+
+
+
+
+
+ 2
+ docname
+
+ Data
+
+ Docname
+
+
+
+
+
+
+ 3
+ doclist_json
+
+ Code
+
+ Doclist JSON
+
+
+
+
+
+
+
+
+
+
+
Controller
+
frappe.core.doctype.version.version
+
+
+
+
+
+
+
+
Class Version
+
+
Inherits from frappe.model.document.Document
+
+
+
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.core.doctype.version.version.restore
+
+
+
+
+ frappe.core.doctype.version.version.restore
+ (version)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/custom/custom_field.html b/frappe/docs/current/models/custom/custom_field.html
new file mode 100644
index 0000000000..1ec7648569
--- /dev/null
+++ b/frappe/docs/current/models/custom/custom_field.html
@@ -0,0 +1,668 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
Table Name: tabCustom Field
+
+
+Adds a custom field to a DocType
+
+
Fields
+
+
+
+
+ Sr
+ Fieldname
+ Type
+ Label
+ Options
+
+
+
+
+
+ 1
+ dt
+
+ Link
+
+ Document
+
+
+
+
+
+
+
+DocType
+
+
+
+
+
+
+
+ 2
+ label
+
+ Data
+
+ Label
+
+
+
+
+
+
+ 3
+ label_help
+
+ HTML
+
+ Label Help
+
+
+
+
+
+
+ 4
+ fieldname
+
+ Data
+
+ Fieldname
+
+
+
+
+
+
+ 5
+ insert_after
+
+ Select
+
+ Insert After
+
+ Select the label after which you want to insert new field.
+
+
+
+
+
+ 6
+ column_break_6
+
+ Column Break
+
+
+
+
+
+
+
+
+ 7
+ fieldtype
+
+ Select
+
+ Field Type
+
+
+
+ Attach
+Button
+Check
+Code
+Column Break
+Currency
+Data
+Date
+Datetime
+Dynamic Link
+Float
+HTML
+Image
+Int
+Link
+Long Text
+Password
+Percent
+Read Only
+Section Break
+Select
+Small Text
+Table
+Text
+Text Editor
+Time
+
+
+
+
+ 8
+ precision
+
+ Select
+
+ Precision
+
+ Set non-standard precision for a Float or Currency field
+
+
+
+1
+2
+3
+4
+5
+6
+7
+8
+9
+
+
+
+
+ 9
+ options
+
+ Text
+
+ Options
+
+
+
+
+
+
+ 10
+ options_help
+
+ HTML
+
+ Options Help
+
+
+
+
+
+
+ 11
+ section_break_11
+
+ Section Break
+
+
+
+
+
+
+
+
+ 12
+ collapsible
+
+ Check
+
+ Collapsible
+
+
+
+
+
+
+ 13
+ collapsible_depends_on
+
+ Data
+
+ Collapsible Depends On
+
+
+
+
+
+
+ 14
+ default
+
+ Text
+
+ Default Value
+
+
+
+
+
+
+ 15
+ depends_on
+
+ Small Text
+
+ Depends On
+
+
+
+
+
+
+ 16
+ description
+
+ Text
+
+ Field Description
+
+
+
+
+
+
+ 17
+ permlevel
+
+ Int
+
+ Permission Level
+
+
+
+
+
+
+ 18
+ width
+
+ Data
+
+ Width
+
+
+
+
+
+
+ 19
+ properties
+
+ Column Break
+
+
+
+
+
+
+
+
+ 20
+ reqd
+
+ Check
+
+ Is Mandatory Field
+
+
+
+
+
+
+ 21
+ unique
+
+ Check
+
+ Unique
+
+
+
+
+
+
+ 22
+ read_only
+
+ Check
+
+ Read Only
+
+
+
+
+
+
+ 23
+ ignore_user_permissions
+
+ Check
+
+ Ignore User Permissions
+
+
+
+
+
+
+ 24
+ hidden
+
+ Check
+
+ Hidden
+
+
+
+
+
+
+ 25
+ print_hide
+
+ Check
+
+ Print Hide
+
+
+
+
+
+
+ 26
+ print_hide_if_no_value
+
+ Check
+
+ Print Hide If No Value
+
+
+
+
+
+
+ 27
+ print_width
+
+ Data
+
+ Print Width
+
+
+
+
+
+
+ 28
+ no_copy
+
+ Check
+
+ No Copy
+
+
+
+
+
+
+ 29
+ allow_on_submit
+
+ Check
+
+ Allow on Submit
+
+
+
+
+
+
+ 30
+ in_filter
+
+ Check
+
+ In Report Filter
+
+
+
+
+
+
+ 31
+ in_list_view
+
+ Check
+
+ In List View
+
+
+
+
+
+
+ 32
+ report_hide
+
+ Check
+
+ Report Hide
+
+
+
+
+
+
+ 33
+ search_index
+
+ Check
+
+ Index
+
+
+
+
+
+
+
+
+
+
+
Controller
+
frappe.custom.doctype.custom_field.custom_field
+
+
+
+
+
+
+
+
Class CustomField
+
+
Inherits from frappe.model.document.Document
+
+
+
+
+
+
+
+
+
+
+ autoname
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ on_trash
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ on_update
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ set_fieldname
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ set_property_setter_for_idx
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ validate
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ validate_insert_after
+ (self, meta)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.custom.doctype.custom_field.custom_field.create_custom_field
+ (doctype, df)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.custom.doctype.custom_field.custom_field.create_custom_field_if_values_exist
+ (doctype, df)
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.custom.doctype.custom_field.custom_field.get_fields_label
+
+
+
+
+ frappe.custom.doctype.custom_field.custom_field.get_fields_label
+ (doctype=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/custom/custom_script.html b/frappe/docs/current/models/custom/custom_script.html
new file mode 100644
index 0000000000..4726e71823
--- /dev/null
+++ b/frappe/docs/current/models/custom/custom_script.html
@@ -0,0 +1,178 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
Table Name: tabCustom Script
+
+
+Adds a custom script (client or server) to a DocType
+
+
Fields
+
+
+
+
+ Sr
+ Fieldname
+ Type
+ Label
+ Options
+
+
+
+
+
+ 1
+ dt
+
+ Link
+
+ DocType
+
+
+
+
+
+
+
+DocType
+
+
+
+
+
+
+
+ 2
+ script_type
+
+ Select
+
+ Script Type
+
+
+
+ Client
+
+
+
+
+ 3
+ script
+
+ Code
+
+ Script
+
+
+
+ Script
+
+
+
+
+ 4
+ sample
+
+ HTML
+
+ Sample
+
+
+
+
+
+
+
+
+
+
+
Controller
+
frappe.custom.doctype.custom_script.custom_script
+
+
+
+
+
+
+
+
Class CustomScript
+
+
Inherits from frappe.model.document.Document
+
+
+
+
+
+
+
+
+
+
+ autoname
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ on_trash
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ on_update
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/custom/customize_form.html b/frappe/docs/current/models/custom/customize_form.html
new file mode 100644
index 0000000000..8a88c8a0dc
--- /dev/null
+++ b/frappe/docs/current/models/custom/customize_form.html
@@ -0,0 +1,484 @@
+
+
+
+
+
+
+
+
+
Single
+
+
+
+
+
+
+
Fields
+
+
+
+
+ Sr
+ Fieldname
+ Type
+ Label
+ Options
+
+
+
+
+
+ 1
+ doc_type
+
+ Link
+
+ Enter Form Type
+
+
+
+
+
+
+
+DocType
+
+
+
+
+
+
+
+ 2
+ properties
+
+ Section Break
+
+
+
+
+
+
+
+
+ 3
+ default_print_format
+
+ Link
+
+ Default Print Format
+
+
+
+
+
+
+
+Print Format
+
+
+
+
+
+
+
+ 4
+ max_attachments
+
+ Int
+
+ Max Attachments
+
+
+
+
+
+
+ 5
+ allow_copy
+
+ Check
+
+ Hide Copy
+
+
+
+
+
+
+ 6
+ column_break_5
+
+ Column Break
+
+
+
+
+
+
+
+
+ 7
+ title_field
+
+ Data
+
+ Title Field
+
+ Use this fieldname to generate title
+
+
+
+
+
+ 8
+ search_fields
+
+ Data
+
+ Search Fields
+
+ Fields separated by comma (,) will be included in the "Search By" list of Search dialog box
+
+
+
+
+
+ 9
+ section_break_8
+
+ Section Break
+
+
+
+
+
+
+
+
+ 10
+ sort_field
+
+ Select
+
+ Sort Field
+
+
+
+
+
+
+ 11
+ column_break_10
+
+ Column Break
+
+
+
+
+
+
+
+
+ 12
+ sort_order
+
+ Select
+
+ Sort Order
+
+
+
+ ASC
+DESC
+
+
+
+
+ 13
+ fields_section_break
+
+ Section Break
+
+ Fields
+
+ Customize Label, Print Hide, Default etc.
+
+
+
+
+
+ 14
+ fields
+
+ Table
+
+ Fields
+
+
+
+
+
+
+
+Customize Form Field
+
+
+
+
+
+
+
+
+
+
+
+
Controller
+
frappe.custom.doctype.customize_form.customize_form
+
+
+
+
+
+
+
+
Class CustomizeForm
+
+
Inherits from frappe.model.document.Document
+
+
+
+
+
+
+
+
+
+
+ add_custom_field
+ (self, df)
+
+
+
+
+
+
+
+
+
+
+
+ clear_existing_doc
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ delete_custom_fields
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ delete_existing_property_setter
+ (self, property, fieldname=None)
+
+
+
+
+
+
+
+
+
+
+
+ fetch_to_customize
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ get_existing_property_value
+ (self, property_name, fieldname=None)
+
+
+
+
+
+
+
+
+
+
+
+ make_property_setter
+ (self, property, value, property_type, fieldname=None)
+
+
+
+
+
+
+
+
+
+
+
+ on_update
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ reset_to_defaults
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ save_customization
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ set_idx_property_setter
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ set_property_setters
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ update_custom_fields
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ update_in_custom_field
+ (self, df)
+
+
+
+
+
+
+
+
+
+
+
+ validate_fieldtype_change
+ (self, df, old_value, new_value)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/custom/customize_form_field.html b/frappe/docs/current/models/custom/customize_form_field.html
new file mode 100644
index 0000000000..1dae6bcfdd
--- /dev/null
+++ b/frappe/docs/current/models/custom/customize_form_field.html
@@ -0,0 +1,496 @@
+
+
+
+
+
+
+
+
+
+
Child Table
+
+
+
Table Name: tabCustomize Form Field
+
+
+
+
+
Fields
+
+
+
+
+ Sr
+ Fieldname
+ Type
+ Label
+ Options
+
+
+
+
+
+ 1
+ label_and_type
+
+ Section Break
+
+ Label and Type
+
+
+
+
+
+
+ 2
+ label
+
+ Data
+
+ Label
+
+
+
+
+
+
+ 3
+ fieldtype
+
+ Select
+
+ Type
+
+
+
+ Attach
+Attach Image
+Button
+Check
+Code
+Column Break
+Currency
+Data
+Date
+Datetime
+Dynamic Link
+Float
+Fold
+Heading
+HTML
+Image
+Int
+Link
+Long Text
+Password
+Percent
+Read Only
+Section Break
+Select
+Small Text
+Table
+Text
+Text Editor
+Time
+
+
+
+
+ 4
+ fieldname
+
+ Data
+
+ Name
+
+
+
+
+
+
+ 5
+ reqd
+
+ Check
+
+ Mandatory
+
+
+
+
+
+
+ 6
+ unique
+
+ Check
+
+ Unique
+
+
+
+
+
+
+ 7
+ in_list_view
+
+ Check
+
+ In List View
+
+
+
+
+
+
+ 8
+ column_break_7
+
+ Column Break
+
+
+
+
+
+
+
+
+ 9
+ precision
+
+ Select
+
+ Precision
+
+ Set non-standard precision for a Float or Currency field
+
+
+
+1
+2
+3
+4
+5
+6
+7
+8
+9
+
+
+
+
+ 10
+ length
+
+ Int
+
+ Length
+
+
+
+
+
+
+ 11
+ options
+
+ Text
+
+ Options
+
+ For Links, enter the DocType as range.
+For Select, enter list of Options, each on a new line.
+
+
+
+
+
+ 12
+ permissions
+
+ Section Break
+
+ Permissions
+
+
+
+
+
+
+ 13
+ depends_on
+
+ Data
+
+ Depends On
+
+ This field will appear only if the fieldname defined here has value OR the rules are true (examples):
+myfield
+eval:doc.myfield=='My Value'
+eval:doc.age>18
+
+
+
+
+
+ 14
+ permlevel
+
+ Int
+
+ Perm Level
+
+
+
+
+
+
+ 15
+ hidden
+
+ Check
+
+ Hidden
+
+
+
+
+
+
+ 16
+ read_only
+
+ Check
+
+ Read Only
+
+
+
+
+
+
+ 17
+ collapsible
+
+ Check
+
+ Collapsible
+
+
+
+
+
+
+ 18
+ collapsible_depends_on
+
+ Data
+
+ Collapsible Depends On
+
+
+
+
+
+
+ 19
+ column_break_14
+
+ Column Break
+
+
+
+
+
+
+
+
+ 20
+ ignore_user_permissions
+
+ Check
+
+ Ignore User Permissions
+
+
+
+
+
+
+ 21
+ allow_on_submit
+
+ Check
+
+ Allow on Submit
+
+
+
+
+
+
+ 22
+ report_hide
+
+ Check
+
+ Report Hide
+
+
+
+
+
+
+ 23
+ display
+
+ Section Break
+
+ Display
+
+
+
+
+
+
+ 24
+ default
+
+ Text
+
+ Default
+
+
+
+
+
+
+ 25
+ in_filter
+
+ Check
+
+ In Filter
+
+
+
+
+
+
+ 26
+ column_break_21
+
+ Column Break
+
+
+
+
+
+
+
+
+ 27
+ description
+
+ Text
+
+ Description
+
+
+
+
+
+
+ 28
+ print_hide
+
+ Check
+
+ Print Hide
+
+
+
+
+
+
+ 29
+ print_hide_if_no_value
+
+ Check
+
+ Print Hide If No Value
+
+
+
+
+
+
+ 30
+ print_width
+
+ Data
+
+ Print Width
+
+ Print Width of the field, if the field is a column in a table
+
+
+
+
+
+ 31
+ width
+
+ Data
+
+ Width
+
+
+
+
+
+
+ 32
+ is_custom_field
+
+ Check
+
+ Is Custom Field
+
+
+
+
+
+
+
+
+
+
+
+
Child Table Of
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/custom/index.html b/frappe/docs/current/models/custom/index.html
new file mode 100644
index 0000000000..f439166e78
--- /dev/null
+++ b/frappe/docs/current/models/custom/index.html
@@ -0,0 +1,19 @@
+
+
+
+
+
+
DocTypes for custom
+
+{index}
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/custom/index.txt b/frappe/docs/current/models/custom/index.txt
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/frappe/docs/current/models/custom/property_setter.html b/frappe/docs/current/models/custom/property_setter.html
new file mode 100644
index 0000000000..e704d53dfc
--- /dev/null
+++ b/frappe/docs/current/models/custom/property_setter.html
@@ -0,0 +1,324 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
Table Name: tabProperty Setter
+
+
+Property Setter overrides a standard DocType or Field property
+
+
Fields
+
+
+
+
+ Sr
+ Fieldname
+ Type
+ Label
+ Options
+
+
+
+
+
+ 1
+ help
+
+ HTML
+
+ Help
+
+
+
+
+
+
+ 2
+ sb0
+
+ Section Break
+
+
+
+
+
+
+
+
+ 3
+ doctype_or_field
+
+ Select
+
+ DocType or Field
+
+
+
+
+DocField
+DocType
+
+
+
+
+ 4
+ value
+
+ Text
+
+ Set Value
+
+ New value to be set
+
+
+
+
+
+ 5
+ column_break0
+
+ Column Break
+
+
+
+
+
+
+
+
+ 6
+ doc_type
+
+ Link
+
+ DocType
+
+
+
+
+
+
+
+DocType
+
+
+
+
+
+
+
+ 7
+ field_name
+
+ Data
+
+ Field Name
+
+ ID (name) of the entity whose property is to be set
+
+
+
+
+
+ 8
+ property
+
+ Data
+
+ Property
+
+
+
+
+
+
+ 9
+ property_type
+
+ Data
+
+ Property Type
+
+
+
+
+
+
+ 10
+ default_value
+
+ Data
+
+ Default Value
+
+
+
+
+
+
+
+
+
+
+
Controller
+
frappe.custom.doctype.property_setter.property_setter
+
+
+
+
+
+
+
+
Class PropertySetter
+
+
Inherits from frappe.model.document.Document
+
+
+
+
+
+
+
+
+
+
+ autoname
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ get_defaults
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ get_field_ids
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ get_property_list
+ (self, dt)
+
+
+
+
+
+
+
+
+
+
+
+ get_setup_data
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ on_update
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ validate
+ (self)
+
+
delete other property setters on this, if this is new
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.custom.doctype.property_setter.property_setter.make_property_setter
+ (doctype, fieldname, property, value, property_type, for_doctype=False, validate_fields_for_doctype=True)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/desk/event.html b/frappe/docs/current/models/desk/event.html
new file mode 100644
index 0000000000..57428d8f78
--- /dev/null
+++ b/frappe/docs/current/models/desk/event.html
@@ -0,0 +1,536 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
Table Name: tabEvent
+
+
+
+
+
Fields
+
+
+
+
+ Sr
+ Fieldname
+ Type
+ Label
+ Options
+
+
+
+
+
+ 1
+ details
+
+ Section Break
+
+
+
+
+
+
+
+
+ 2
+ subject
+
+ Data
+
+ Subject
+
+
+
+
+
+
+ 3
+ event_type
+
+ Select
+
+ Event Type
+
+
+
+ Private
+Public
+Cancel
+
+
+
+
+ 4
+ send_reminder
+
+ Check
+
+ Send an email reminder in the morning
+
+
+
+
+
+
+ 5
+ column_break_4
+
+ Column Break
+
+
+
+
+
+
+
+
+ 6
+ starts_on
+
+ Datetime
+
+ Starts on
+
+
+
+
+
+
+ 7
+ ends_on
+
+ Datetime
+
+ Ends on
+
+
+
+
+
+
+ 8
+ all_day
+
+ Check
+
+ All Day
+
+
+
+
+
+
+ 9
+ section_break_8
+
+ Section Break
+
+
+
+
+
+
+
+
+ 10
+ repeat_this_event
+
+ Check
+
+ Repeat this Event
+
+
+
+
+
+
+ 11
+ section_break_11
+
+ Section Break
+
+
+
+
+
+
+
+
+ 12
+ repeat_on
+
+ Select
+
+ Repeat On
+
+
+
+
+Every Day
+Every Week
+Every Month
+Every Year
+
+
+
+
+ 13
+ repeat_till
+
+ Date
+
+ Repeat Till
+
+ Leave blank to repeat always
+
+
+
+
+
+ 14
+ column_break_11
+
+ Column Break
+
+
+
+
+
+
+
+
+ 15
+ monday
+
+ Check
+
+ Monday
+
+
+
+
+
+
+ 16
+ tuesday
+
+ Check
+
+ Tuesday
+
+
+
+
+
+
+ 17
+ wednesday
+
+ Check
+
+ Wednesday
+
+
+
+
+
+
+ 18
+ thursday
+
+ Check
+
+ Thursday
+
+
+
+
+
+
+ 19
+ friday
+
+ Check
+
+ Friday
+
+
+
+
+
+
+ 20
+ saturday
+
+ Check
+
+ Saturday
+
+
+
+
+
+
+ 21
+ sunday
+
+ Check
+
+ Sunday
+
+
+
+
+
+
+ 22
+ section_break_6
+
+ Section Break
+
+
+
+
+
+
+
+
+ 23
+ description
+
+ Text Editor
+
+ Description
+
+
+
+
+
+
+ 24
+ participants
+
+ Section Break
+
+ Participants
+
+
+
+
+
+
+ 25
+ groups
+
+ Column Break
+
+ Groups
+
+
+
+
+
+
+ 26
+ roles
+
+ Table
+
+ Roles
+
+
+
+
+
+
+
+Event Role
+
+
+
+
+
+
+
+ 27
+ ref_type
+
+ Link
+
+ Ref Type
+
+
+
+
+
+
+
+DocType
+
+
+
+
+
+
+
+ 28
+ ref_name
+
+ Dynamic Link
+
+ Ref Name
+
+
+
+ ref_type
+
+
+
+
+
+
+
+
+
Controller
+
frappe.desk.doctype.event.event
+
+
+
+
+
+
+
+
Class Event
+
+
Inherits from frappe.model.document.Document
+
+
+
+
+
+
+
+
+
+
+ get_route
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ validate
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.desk.doctype.event.event.get_events
+
+
+
+
+ frappe.desk.doctype.event.event.get_events
+ (start, end, user=None, for_reminder=False)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.doctype.event.event.get_permission_query_conditions
+ (user)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.doctype.event.event.has_permission
+ (doc, user)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.doctype.event.event.send_event_digest
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/desk/event_role.html b/frappe/docs/current/models/desk/event_role.html
new file mode 100644
index 0000000000..78d0814dda
--- /dev/null
+++ b/frappe/docs/current/models/desk/event_role.html
@@ -0,0 +1,84 @@
+
+
+
+
+
+
+
+
+
+
Child Table
+
+
+
Table Name: tabEvent Role
+
+
+
+
+
Fields
+
+
+
+
+ Sr
+ Fieldname
+ Type
+ Label
+ Options
+
+
+
+
+
+ 1
+ role
+
+ Link
+
+ Role
+
+
+
+
+
+
+
+Role
+
+
+
+
+
+
+
+
+
+
+
+
+
Child Table Of
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/desk/feed.html b/frappe/docs/current/models/desk/feed.html
new file mode 100644
index 0000000000..827a680734
--- /dev/null
+++ b/frappe/docs/current/models/desk/feed.html
@@ -0,0 +1,233 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
Table Name: tabFeed
+
+
+
+
+
Fields
+
+
+
+
+ Sr
+ Fieldname
+ Type
+ Label
+ Options
+
+
+
+
+
+ 1
+ feed_type
+
+ Select
+
+ Feed Type
+
+
+
+
+Comment
+Login
+Label
+Info
+
+
+
+
+ 2
+ doc_type
+
+ Data
+
+ Doc Type
+
+
+
+
+
+
+ 3
+ doc_name
+
+ Data
+
+ Doc Name
+
+
+
+
+
+
+ 4
+ subject
+
+ Small Text
+
+ Subject
+
+
+
+
+
+
+ 5
+ color
+
+ Data
+
+ Color
+
+
+
+
+
+
+ 6
+ full_name
+
+ Data
+
+ Full Name
+
+
+
+
+
+
+
+
+
+
+
Controller
+
frappe.desk.doctype.feed.feed
+
+
+
+
+
+
+
+
Class Feed
+
+
Inherits from frappe.model.document.Document
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.doctype.feed.feed.get_permission_query_conditions
+ (user)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.doctype.feed.feed.has_permission
+ (doc, user)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.doctype.feed.feed.login_feed
+ (login_manager)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.doctype.feed.feed.on_doctype_update
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.doctype.feed.feed.update_feed
+ (doc, method=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/desk/index.html b/frappe/docs/current/models/desk/index.html
new file mode 100644
index 0000000000..1be2dcca6f
--- /dev/null
+++ b/frappe/docs/current/models/desk/index.html
@@ -0,0 +1,19 @@
+
+
+
+
+
+
DocTypes for desk
+
+{index}
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/desk/index.txt b/frappe/docs/current/models/desk/index.txt
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/frappe/docs/current/models/desk/note.html b/frappe/docs/current/models/desk/note.html
new file mode 100644
index 0000000000..2bedbdcbb4
--- /dev/null
+++ b/frappe/docs/current/models/desk/note.html
@@ -0,0 +1,173 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
Table Name: tabNote
+
+
+Note is a free page where users can share documents / notes
+
+
Fields
+
+
+
+
+ Sr
+ Fieldname
+ Type
+ Label
+ Options
+
+
+
+
+
+ 1
+ title
+
+ Data
+
+ Title
+
+
+
+
+
+
+ 2
+ public
+
+ Check
+
+ Public
+
+ Everyone can read
+
+
+
+
+
+ 3
+ content
+
+ Text Editor
+
+ Content
+
+ Help: To link to another record in the system, use "#Form/Note/[Note Name]" as the Link URL. (don't use "http://")
+
+
+
+
+
+
+
+
+
+
Controller
+
frappe.desk.doctype.note.note
+
+
+
+
+
+
+
+
Class Note
+
+
Inherits from frappe.model.document.Document
+
+
+
+
+
+
+
+
+
+
+ autoname
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ before_print
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.doctype.note.note.get_permission_query_conditions
+ (user)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.doctype.note.note.has_permission
+ (doc, ptype, user)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/desk/todo.html b/frappe/docs/current/models/desk/todo.html
new file mode 100644
index 0000000000..84de14cb09
--- /dev/null
+++ b/frappe/docs/current/models/desk/todo.html
@@ -0,0 +1,406 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
Table Name: tabToDo
+
+
+
+
+
Fields
+
+
+
+
+ Sr
+ Fieldname
+ Type
+ Label
+ Options
+
+
+
+
+
+ 1
+ description_and_status
+
+ Section Break
+
+ Description and Status
+
+
+
+
+
+
+ 2
+ description
+
+ Text
+
+ Description
+
+
+
+
+
+
+ 3
+ column_break_2
+
+ Column Break
+
+
+
+
+
+
+
+
+ 4
+ status
+
+ Select
+
+ Status
+
+
+
+ Open
+Closed
+
+
+
+
+ 5
+ priority
+
+ Select
+
+ Priority
+
+
+
+ High
+Medium
+Low
+
+
+
+
+ 6
+ date
+
+ Date
+
+ Due Date
+
+
+
+
+
+
+ 7
+ owner
+
+ Link
+
+ Allocated To
+
+
+
+
+
+
+
+User
+
+
+
+
+
+
+
+ 8
+ section_break_6
+
+ Section Break
+
+ Reference
+
+
+
+
+
+
+ 9
+ reference_type
+
+ Link
+
+ Reference Type
+
+
+
+
+
+
+
+DocType
+
+
+
+
+
+
+
+ 10
+ reference_name
+
+ Dynamic Link
+
+ Reference Name
+
+
+
+ reference_type
+
+
+
+
+ 11
+ column_break_10
+
+ Column Break
+
+
+
+
+
+
+
+
+ 12
+ role
+
+ Link
+
+ Role
+
+
+
+
+
+
+
+Role
+
+
+
+
+
+
+
+ 13
+ assigned_by
+
+ Link
+
+ Assigned By
+
+
+
+
+
+
+
+User
+
+
+
+
+
+
+
+ 14
+ sender
+
+ Data
+
+ Sender
+
+
+
+
+
+
+
+
+
+
+
Controller
+
frappe.desk.doctype.todo.todo
+
+
+
+
+
+
+
+
Class ToDo
+
+
Inherits from frappe.model.document.Document
+
+
+
+
+
+
+
+
+
+
+ add_assign_comment
+ (self, text, comment_type)
+
+
+
+
+
+
+
+
+
+
+
+ on_trash
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ on_update
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ update_in_reference
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ validate
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.doctype.todo.todo.get_permission_query_conditions
+ (user)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.doctype.todo.todo.has_permission
+ (doc, user)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.desk.doctype.todo.todo.on_doctype_update
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/doctype/index.html b/frappe/docs/current/models/doctype/index.html
new file mode 100644
index 0000000000..0f09fc8a53
--- /dev/null
+++ b/frappe/docs/current/models/doctype/index.html
@@ -0,0 +1,19 @@
+
+
+
+
+
+
DocTypes for doctype
+
+{index}
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/doctype/index.txt b/frappe/docs/current/models/doctype/index.txt
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/frappe/docs/current/models/email/bulk_email.html b/frappe/docs/current/models/email/bulk_email.html
new file mode 100644
index 0000000000..ca1139a940
--- /dev/null
+++ b/frappe/docs/current/models/email/bulk_email.html
@@ -0,0 +1,217 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
Table Name: tabBulk Email
+
+
+Bulk Email records.
+
+
Fields
+
+
+
+
+ Sr
+ Fieldname
+ Type
+ Label
+ Options
+
+
+
+
+
+ 1
+ sender
+
+ Data
+
+ Sender
+
+
+
+
+
+
+ 2
+ recipient
+
+ Data
+
+ Recipient
+
+
+
+
+
+
+ 3
+ message
+
+ Code
+
+ Message
+
+
+
+
+
+
+ 4
+ status
+
+ Select
+
+ Status
+
+
+
+
+Not Sent
+Sending
+Sent
+Error
+Expired
+
+
+
+
+ 5
+ error
+
+ Text
+
+ Error
+
+
+
+
+
+
+ 6
+ reference_doctype
+
+ Link
+
+ Reference DocType
+
+
+
+
+
+
+
+DocType
+
+
+
+
+
+
+
+ 7
+ reference_name
+
+ Data
+
+ Reference DocName
+
+
+
+
+
+
+ 8
+ send_after
+
+ Datetime
+
+ Send After
+
+
+
+
+
+
+ 9
+ priority
+
+ Int
+
+ Priority
+
+
+
+
+
+
+
+
+
+
+
Controller
+
frappe.email.doctype.bulk_email.bulk_email
+
+
+
+
+
+
+
+
Class BulkEmail
+
+
Inherits from frappe.model.document.Document
+
+
+
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.email.doctype.bulk_email.bulk_email.retry_sending
+
+
+
+
+ frappe.email.doctype.bulk_email.bulk_email.retry_sending
+ (name)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/email/email_account.html b/frappe/docs/current/models/email/email_account.html
new file mode 100644
index 0000000000..65100caf1a
--- /dev/null
+++ b/frappe/docs/current/models/email/email_account.html
@@ -0,0 +1,780 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
Table Name: tabEmail Account
+
+
+
+
+
Fields
+
+
+
+
+ Sr
+ Fieldname
+ Type
+ Label
+ Options
+
+
+
+
+
+ 1
+ email_settings
+
+ Section Break
+
+
+
+
+
+
+
+
+ 2
+ service
+
+ Select
+
+ Service
+
+
+
+
+GMail
+Yahoo Mail
+Outlook.com
+Yandex.Mail
+
+
+
+
+ 3
+ email_id
+
+ Data
+
+ Email Id
+
+
+
+ Email
+
+
+
+
+ 4
+ login_id_is_different
+
+ Check
+
+ Login Id is Different
+
+
+
+
+
+
+ 5
+ login_id
+
+ Data
+
+ Login Id
+
+
+
+
+
+
+ 6
+ password
+
+ Password
+
+ Password
+
+
+
+
+
+
+ 7
+ email_account_name
+
+ Data
+
+ Email Account Name
+
+ e.g. "Support", "Sales", "Jerry Yang"
+
+
+
+
+
+ 8
+ mailbox_settings
+
+ Section Break
+
+
+
+
+
+
+
+
+ 9
+ enable_incoming
+
+ Check
+
+ Enable Incoming
+
+ Check this to pull emails from your mailbox
+
+
+
+
+
+ 10
+ use_imap
+
+ Check
+
+ Use IMAP
+
+
+
+
+
+
+ 11
+ email_server
+
+ Data
+
+ Email Server
+
+ e.g. pop.gmail.com / imap.gmail.com
+
+
+
+
+
+ 12
+ use_ssl
+
+ Check
+
+ Use SSL
+
+
+
+
+
+
+ 13
+ attachment_limit
+
+ Int
+
+ Attachment Limit (MB)
+
+ Ignore attachments over this size
+
+
+
+
+
+ 14
+ append_to
+
+ Link
+
+ Append To
+
+ Append as communication against this DocType (must have fields, "Status", "Subject")
+
+
+
+
+
+
+DocType
+
+
+
+
+
+
+
+ 15
+ default_incoming
+
+ Check
+
+ Default Incoming
+
+ e.g. replies@yourcomany.com. All replies will come to this inbox.
+
+
+
+
+
+ 16
+ section_break_13
+
+ Section Break
+
+
+
+
+
+
+
+
+ 17
+ notify_if_unreplied
+
+ Check
+
+ Notify if unreplied
+
+
+
+
+
+
+ 18
+ unreplied_for_mins
+
+ Int
+
+ Notify if unreplied for (in mins)
+
+
+
+
+
+
+ 19
+ send_notification_to
+
+ Small Text
+
+ Send Notification to
+
+ Email Ids
+
+
+
+
+
+ 20
+ outgoing_mail_settings
+
+ Section Break
+
+
+
+
+
+
+
+
+ 21
+ enable_outgoing
+
+ Check
+
+ Enable Outgoing
+
+ SMTP Settings for outgoing emails
+
+
+
+
+
+ 22
+ smtp_server
+
+ Data
+
+ SMTP Server
+
+ e.g. smtp.gmail.com
+
+
+
+
+
+ 23
+ use_tls
+
+ Check
+
+ Use TLS
+
+
+
+
+
+
+ 24
+ smtp_port
+
+ Data
+
+ Port
+
+ If non standard port (e.g. 587)
+
+
+
+
+
+ 25
+ default_outgoing
+
+ Check
+
+ Default Outgoing
+
+ Notifications and bulk mails will be sent from this outgoing server.
+
+
+
+
+
+ 26
+ always_use_account_email_id_as_sender
+
+ Check
+
+ Always use Account's Email ID as Sender
+
+ Uses the Email ID mentioned in this Account as the Sender for all emails sent using this Account.
+
+
+
+
+
+ 27
+ signature_section
+
+ Section Break
+
+
+
+
+
+
+
+
+ 28
+ add_signature
+
+ Check
+
+ Add Signature
+
+
+
+
+
+
+ 29
+ signature
+
+ Text Editor
+
+ Signature
+
+
+
+
+
+
+ 30
+ auto_reply
+
+ Section Break
+
+
+
+
+
+
+
+
+ 31
+ enable_auto_reply
+
+ Check
+
+ Enable Auto Reply
+
+
+
+
+
+
+ 32
+ auto_reply_message
+
+ Text Editor
+
+ Auto Reply Message
+
+ ProTip: Add Reference: {{ reference_doctype }} {{ reference_name }} to send document reference
+
+
+
+
+
+ 33
+ set_footer
+
+ Section Break
+
+
+
+
+
+
+
+
+ 34
+ footer
+
+ Text Editor
+
+ Footer
+
+
+
+
+
+
+
+
+
+
+
Controller
+
frappe.email.doctype.email_account.email_account
+
+
+
+
+
+
+
+
Class EmailAccount
+
+
Inherits from frappe.model.document.Document
+
+
+
+
+
+
+
+
+
+
+ autoname
+ (self)
+
+
Set name as email_account_name or make title from email id.
+
+
+
+
+
+
+
+
+
+
+ check_smtp
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ get_server
+ (self, in_receive=False)
+
+
Returns logged in POP3 connection object.
+
+
+
+
+
+
+
+
+
+
+ get_unreplied_notification_emails
+ (self)
+
+
Return list of emails listed
+
+
+
+
+
+
+
+
+
+
+ handle_incoming_connect_error
+ (self, description)
+
+
+
+
+
+
+
+
+
+
+
+ insert_communication
+ (self, raw)
+
+
+
+
+
+
+
+
+
+
+
+ on_trash
+ (self)
+
+
Clear communications where email account is linked
+
+
+
+
+
+
+
+
+
+
+ on_update
+ (self)
+
+
Check there is only one default of each type.
+
+
+
+
+
+
+
+
+
+
+ receive
+ (self, test_mails=None)
+
+
Called by scheduler to receive emails from this EMail account using POP3/IMAP.
+
+
+
+
+
+
+
+
+
+
+ send_auto_reply
+ (self, communication, email)
+
+
Send auto reply if set.
+
+
+
+
+
+
+
+
+
+
+ set_thread
+ (self, communication, email)
+
+
Appends communication to parent based on thread ID. Will extract
+parent communication and will link the communication to the reference of that
+communication. Also set the status of parent transaction to Open or Replied.
+
+
If no thread id is found and append_to is set for the email account,
+it will create a new parent transaction (e.g. Issue)
+
+
+
+
+
+
+
+
+
+
+ there_must_be_only_one_default
+ (self)
+
+
If current Email Account is default, un-default all other accounts.
+
+
+
+
+
+
+
+
+
+
+ validate
+ (self)
+
+
Validate email id and check POP3/IMAP and SMTP connections is enabled.
+
+
+
+
+
+
+
+
+
+
+
+
Class SentEmailInInbox
+
+
Inherits from exceptions.Exception
+
+
+
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.email.doctype.email_account.email_account.get_append_to
+
+
+
+
+ frappe.email.doctype.email_account.email_account.get_append_to
+ (doctype=None, txt=None, searchfield=None, start=None, page_len=None, filters=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.email.doctype.email_account.email_account.notify_unreplied
+ ()
+
+
Sends email notifications if there are unreplied Communications
+and notify_if_unreplied is set as true.
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.email.doctype.email_account.email_account.pull
+ (now=False)
+
+
Will be called via scheduler, pull emails from all enabled Email accounts.
+
+
+
+
+
+
+
+
+
Linked In:
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/email/email_alert.html b/frappe/docs/current/models/email/email_alert.html
new file mode 100644
index 0000000000..6714978136
--- /dev/null
+++ b/frappe/docs/current/models/email/email_alert.html
@@ -0,0 +1,387 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
Table Name: tabEmail Alert
+
+
+
+
+
Fields
+
+
+
+
+ Sr
+ Fieldname
+ Type
+ Label
+ Options
+
+
+
+
+
+ 1
+ enabled
+
+ Check
+
+ Enabled
+
+
+
+
+
+
+ 2
+ filters
+
+ Section Break
+
+ Filters
+
+
+
+
+
+
+ 3
+ subject
+
+ Data
+
+ Subject
+
+ To add dynamic subject, use jinja tags like
+
+
+
+
+
+
+
+ 4
+ document_type
+
+ Link
+
+ Document Type
+
+
+
+
+
+
+
+DocType
+
+
+
+
+
+
+
+ 5
+ event
+
+ Select
+
+ Send Alert On
+
+
+
+
+New
+Save
+Submit
+Cancel
+Days After
+Days Before
+Value Change
+
+
+
+
+ 6
+ date_changed
+
+ Select
+
+ Reference Date
+
+ Send alert if date matches this field's value
+
+
+
+
+
+ 7
+ days_in_advance
+
+ Int
+
+ Days Before or After
+
+ Send days before or after the reference date
+
+
+
+
+
+ 8
+ value_changed
+
+ Select
+
+ Value Changed
+
+ Send alert if this field's value changes
+
+
+
+
+
+ 9
+ condition
+
+ Data
+
+ Condition
+
+ Optional: The alert will be sent if this expression is true
+
+
+
+
+
+ 10
+ column_break_6
+
+ Column Break
+
+
+
+
+
+
+
+
+ 11
+ html_7
+
+ HTML
+
+
+
+
+
+
+
+
+ 12
+ column_break_5
+
+ Section Break
+
+ Recipients
+
+
+
+
+
+
+ 13
+ recipients
+
+ Table
+
+ Recipients
+
+
+
+
+
+
+
+Email Alert Recipient
+
+
+
+
+
+
+
+ 14
+ message_sb
+
+ Section Break
+
+ Message
+
+
+
+
+
+
+ 15
+ message
+
+ Text
+
+ Message
+
+
+
+
+
+
+ 16
+ attach_print
+
+ Check
+
+ Attach Print
+
+
+
+
+
+
+ 17
+ message_examples
+
+ HTML
+
+ Message Examples
+
+
+
+
+
+
+ 18
+ view_properties
+
+ Button
+
+ View Properties (via Customize Form)
+
+
+
+
+
+
+
+
+
+
+
Controller
+
frappe.email.doctype.email_alert.email_alert
+
+
+
+
+
+
+
+
Class EmailAlert
+
+
Inherits from frappe.model.document.Document
+
+
+
+
+
+
+
+
+
+
+ validate
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.email.doctype.email_alert.email_alert.evaluate_alert
+ (doc, alert, event)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.email.doctype.email_alert.email_alert.trigger_daily_alerts
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.email.doctype.email_alert.email_alert.trigger_email_alerts
+ (doc, method=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/email/email_alert_recipient.html b/frappe/docs/current/models/email/email_alert_recipient.html
new file mode 100644
index 0000000000..48927ab561
--- /dev/null
+++ b/frappe/docs/current/models/email/email_alert_recipient.html
@@ -0,0 +1,102 @@
+
+
+
+
+
+
+
+
+
+
Child Table
+
+
+
Table Name: tabEmail Alert Recipient
+
+
+
+
+
Fields
+
+
+
+
+ Sr
+ Fieldname
+ Type
+ Label
+ Options
+
+
+
+
+
+ 1
+ email_by_document_field
+
+ Select
+
+ Email By Document Field
+
+ Optional: Alert will only be sent if value is a valid email id.
+
+
+
+
+
+ 2
+ cc
+
+ Text
+
+ CC
+
+ Optional: Always send to these ids. Each email id on a new row
+
+
+
+
+
+ 3
+ condition
+
+ Data
+
+ Condition
+
+ Expression, Optional
+
+
+
+
+
+
+
+
+
+
+
Child Table Of
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/email/email_unsubscribe.html b/frappe/docs/current/models/email/email_unsubscribe.html
new file mode 100644
index 0000000000..f387811096
--- /dev/null
+++ b/frappe/docs/current/models/email/email_unsubscribe.html
@@ -0,0 +1,162 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
Table Name: tabEmail Unsubscribe
+
+
+
+
+
Fields
+
+
+
+
+ Sr
+ Fieldname
+ Type
+ Label
+ Options
+
+
+
+
+
+ 1
+ email
+
+ Data
+
+ Email
+
+
+
+
+
+
+ 2
+ reference_doctype
+
+ Link
+
+ Reference DocType
+
+
+
+
+
+
+
+DocType
+
+
+
+
+
+
+
+ 3
+ reference_name
+
+ Dynamic Link
+
+ Reference Name
+
+
+
+ reference_doctype
+
+
+
+
+ 4
+ global_unsubscribe
+
+ Check
+
+ Global Unsubscribe
+
+
+
+
+
+
+
+
+
+
+
Controller
+
frappe.email.doctype.email_unsubscribe.email_unsubscribe
+
+
+
+
+
+
+
+
Class EmailUnsubscribe
+
+
Inherits from frappe.model.document.Document
+
+
+
+
+
+
+
+
+
+
+ on_update
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ validate
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/email/index.html b/frappe/docs/current/models/email/index.html
new file mode 100644
index 0000000000..04fb8cf826
--- /dev/null
+++ b/frappe/docs/current/models/email/index.html
@@ -0,0 +1,19 @@
+
+
+
+
+
+
DocTypes for email
+
+{index}
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/email/index.txt b/frappe/docs/current/models/email/index.txt
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/frappe/docs/current/models/email/standard_reply.html b/frappe/docs/current/models/email/standard_reply.html
new file mode 100644
index 0000000000..6f7fbce293
--- /dev/null
+++ b/frappe/docs/current/models/email/standard_reply.html
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
Table Name: tabStandard Reply
+
+
+
+
+
Fields
+
+
+
+
+ Sr
+ Fieldname
+ Type
+ Label
+ Options
+
+
+
+
+
+ 1
+ subject
+
+ Data
+
+ Subject
+
+
+
+
+
+
+ 2
+ response
+
+ Text Editor
+
+ Response
+
+
+
+
+
+
+ 3
+ owner
+
+ Link
+
+ Owner
+
+
+
+
+
+
+
+User
+
+
+
+
+
+
+
+
+
+
+
+
Controller
+
frappe.email.doctype.standard_reply.standard_reply
+
+
+
+
+
+
+
+
Class StandardReply
+
+
Inherits from frappe.model.document.Document
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/geo/country.html b/frappe/docs/current/models/geo/country.html
new file mode 100644
index 0000000000..c4f15589a4
--- /dev/null
+++ b/frappe/docs/current/models/geo/country.html
@@ -0,0 +1,144 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
Table Name: tabCountry
+
+
+
+
+
Fields
+
+
+
+
+ Sr
+ Fieldname
+ Type
+ Label
+ Options
+
+
+
+
+
+ 1
+ country_name
+
+ Data
+
+ Country Name
+
+
+
+
+
+
+ 2
+ date_format
+
+ Data
+
+ Date Format
+
+
+
+
+
+
+ 3
+ time_zones
+
+ Text
+
+ Time Zones
+
+
+
+
+
+
+ 4
+ code
+
+ Data
+
+ Code
+
+
+
+
+
+
+
+
+
+
+
Controller
+
frappe.geo.doctype.country.country
+
+
+
+
+
+
+
+
Class Country
+
+
Inherits from frappe.model.document.Document
+
+
+
+
+
+
+
+
+
+
+
+
+
Linked In:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/geo/currency.html b/frappe/docs/current/models/geo/currency.html
new file mode 100644
index 0000000000..e62f101d7d
--- /dev/null
+++ b/frappe/docs/current/models/geo/currency.html
@@ -0,0 +1,225 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
Table Name: tabCurrency
+
+
+**Currency** Master
+
+
Fields
+
+
+
+
+ Sr
+ Fieldname
+ Type
+ Label
+ Options
+
+
+
+
+
+ 1
+ currency_name
+
+ Data
+
+ Currency Name
+
+
+
+
+
+
+ 2
+ enabled
+
+ Check
+
+ Enabled
+
+
+
+
+
+
+ 3
+ fraction
+
+ Data
+
+ Fraction
+
+ Sub-currency. For e.g. "Cent"
+
+
+
+
+
+ 4
+ fraction_units
+
+ Int
+
+ Fraction Units
+
+ 1 Currency = [?] Fraction
+For e.g. 1 USD = 100 Cent
+
+
+
+
+
+ 5
+ symbol
+
+ Data
+
+ Symbol
+
+ A symbol for this currency. For e.g. $
+
+
+
+
+
+ 6
+ number_format
+
+ Select
+
+ Number Format
+
+ How should this currency be formatted? If not set, will use system defaults
+
+
+
+#,###.##
+#.###,##
+# ###.##
+# ###,##
+#'###.##
+#, ###.##
+#,##,###.##
+#,###.###
+#.###
+#,###
+
+
+
+
+
+
+
+
+
Controller
+
frappe.geo.doctype.currency.currency
+
+
+
+
+
+
+
+
Class Currency
+
+
Inherits from frappe.model.document.Document
+
+
+
+
+
+
+
+
+
+
+ validate
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Linked In:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/geo/index.html b/frappe/docs/current/models/geo/index.html
new file mode 100644
index 0000000000..22ce50a13e
--- /dev/null
+++ b/frappe/docs/current/models/geo/index.html
@@ -0,0 +1,19 @@
+
+
+
+
+
+
DocTypes for geo
+
+{index}
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/geo/index.txt b/frappe/docs/current/models/geo/index.txt
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/frappe/docs/current/models/index.html b/frappe/docs/current/models/index.html
new file mode 100644
index 0000000000..549afa9dfb
--- /dev/null
+++ b/frappe/docs/current/models/index.html
@@ -0,0 +1,21 @@
+
+
+
+
+
+
Browse DocTypes by Module
+
+
Contents
+
+{index}
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/index.txt b/frappe/docs/current/models/index.txt
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/frappe/docs/current/models/integrations/dropbox_backup.html b/frappe/docs/current/models/integrations/dropbox_backup.html
new file mode 100644
index 0000000000..569f43fcd5
--- /dev/null
+++ b/frappe/docs/current/models/integrations/dropbox_backup.html
@@ -0,0 +1,342 @@
+
+
+
+
+
+
+
+
+
Single
+
+
+
+
+
+
+
Fields
+
+
+
+
+ Sr
+ Fieldname
+ Type
+ Label
+ Options
+
+
+
+
+
+ 1
+ send_backups_to_dropbox
+
+ Check
+
+ Send Backups to Dropbox
+
+
+
+
+
+
+ 2
+ upload_backups_to_dropbox
+
+ Select
+
+ Upload Frequency
+
+
+
+ Daily
+Weekly
+
+
+
+
+ 3
+ send_notifications_to
+
+ Data
+
+ Send Notifications To
+
+
+
+
+
+
+ 4
+ dropbox_access_key
+
+ Data
+
+ Dropbox Access Key
+
+
+
+
+
+
+ 5
+ dropbox_access_secret
+
+ Data
+
+ Dropbox Access Secret
+
+
+
+
+
+
+ 6
+ dropbox_access_allowed
+
+ Data
+
+ Dropbox Access Allowed
+
+
+
+
+
+
+ 7
+ allow_dropbox_access
+
+ Button
+
+ Allow Dropbox Access
+
+
+
+
+
+
+
+
+
+
+
Controller
+
frappe.integrations.doctype.dropbox_backup.dropbox_backup
+
+
+
+
+
+
+
+
Class DropboxBackup
+
+
Inherits from frappe.model.document.Document
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.integrations.doctype.dropbox_backup.dropbox_backup.backup_to_dropbox
+ ()
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.integrations.doctype.dropbox_backup.dropbox_backup.dropbox_callback
+
+
+
+
+ frappe.integrations.doctype.dropbox_backup.dropbox_backup.dropbox_callback
+ (oauth_token=None, not_approved=False)
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.integrations.doctype.dropbox_backup.dropbox_backup.get_dropbox_authorize_url
+
+
+
+
+ frappe.integrations.doctype.dropbox_backup.dropbox_backup.get_dropbox_authorize_url
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.integrations.doctype.dropbox_backup.dropbox_backup.get_dropbox_session
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.integrations.doctype.dropbox_backup.dropbox_backup.send_email
+ (success, service_name, error_status=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.integrations.doctype.dropbox_backup.dropbox_backup.take_backups_daily
+ ()
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.integrations.doctype.dropbox_backup.dropbox_backup.take_backups_dropbox
+
+
+
+
+ frappe.integrations.doctype.dropbox_backup.dropbox_backup.take_backups_dropbox
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.integrations.doctype.dropbox_backup.dropbox_backup.take_backups_if
+ (freq)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.integrations.doctype.dropbox_backup.dropbox_backup.take_backups_weekly
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.integrations.doctype.dropbox_backup.dropbox_backup.upload_file_to_dropbox
+ (filename, folder, dropbox_client)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.integrations.doctype.dropbox_backup.dropbox_backup.upload_from_folder
+ (path, dropbox_folder, dropbox_client, did_not_upload, error_log)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/integrations/index.html b/frappe/docs/current/models/integrations/index.html
new file mode 100644
index 0000000000..91072e3cf4
--- /dev/null
+++ b/frappe/docs/current/models/integrations/index.html
@@ -0,0 +1,19 @@
+
+
+
+
+
+
DocTypes for integrations
+
+{index}
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/integrations/index.txt b/frappe/docs/current/models/integrations/index.txt
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/frappe/docs/current/models/integrations/social_login_keys.html b/frappe/docs/current/models/integrations/social_login_keys.html
new file mode 100644
index 0000000000..0697ebae3d
--- /dev/null
+++ b/frappe/docs/current/models/integrations/social_login_keys.html
@@ -0,0 +1,181 @@
+
+
+
+
+
+
+
+
+
Single
+
+
+
+
+
+
+
Fields
+
+
+
+
+ Sr
+ Fieldname
+ Type
+ Label
+ Options
+
+
+
+
+
+ 1
+ facebook
+
+ Section Break
+
+ Facebook
+
+
+
+
+
+
+ 2
+ facebook_client_id
+
+ Data
+
+ Facebook Client ID
+
+
+
+
+
+
+ 3
+ facebook_client_secret
+
+ Data
+
+ Facebook Client Secret
+
+
+
+
+
+
+ 4
+ google
+
+ Section Break
+
+ Google
+
+
+
+
+
+
+ 5
+ google_client_id
+
+ Data
+
+ Google Client ID
+
+
+
+
+
+
+ 6
+ google_client_secret
+
+ Data
+
+ Google Client Secret
+
+
+
+
+
+
+ 7
+ github
+
+ Section Break
+
+ GitHub
+
+
+
+
+
+
+ 8
+ github_client_id
+
+ Data
+
+ GitHub Client ID
+
+
+
+
+
+
+ 9
+ github_client_secret
+
+ Data
+
+ GitHub Client Secret
+
+
+
+
+
+
+
+
+
+
+
Controller
+
frappe.integrations.doctype.social_login_keys.social_login_keys
+
+
+
+
+
+
+
+
Class SocialLoginKeys
+
+
Inherits from frappe.model.document.Document
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/models/index.html b/frappe/docs/current/models/models/index.html
new file mode 100644
index 0000000000..ce9e35ab3e
--- /dev/null
+++ b/frappe/docs/current/models/models/index.html
@@ -0,0 +1,19 @@
+
+
+
+
+
+
DocTypes for models
+
+{index}
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/models/index.txt b/frappe/docs/current/models/models/index.txt
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/frappe/docs/current/models/print/index.html b/frappe/docs/current/models/print/index.html
new file mode 100644
index 0000000000..670fcea219
--- /dev/null
+++ b/frappe/docs/current/models/print/index.html
@@ -0,0 +1,19 @@
+
+
+
+
+
+
DocTypes for print
+
+{index}
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/print/index.txt b/frappe/docs/current/models/print/index.txt
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/frappe/docs/current/models/print/letter_head.html b/frappe/docs/current/models/print/letter_head.html
new file mode 100644
index 0000000000..62675e868f
--- /dev/null
+++ b/frappe/docs/current/models/print/letter_head.html
@@ -0,0 +1,204 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
Table Name: tabLetter Head
+
+
+
+
+
Fields
+
+
+
+
+ Sr
+ Fieldname
+ Type
+ Label
+ Options
+
+
+
+
+
+ 1
+ letter_head_name
+
+ Data
+
+ Letter Head Name
+
+
+
+
+
+
+ 2
+ disabled
+
+ Check
+
+ Disabled
+
+
+
+
+
+
+ 3
+ is_default
+
+ Check
+
+ Is Default
+
+ Check this to make this the default letter head in all prints
+
+
+
+
+
+ 4
+ content
+
+ Text Editor
+
+ Content
+
+ Letter Head in HTML
+
+
+
+
+
+
+
+
+
+
Controller
+
frappe.print.doctype.letter_head.letter_head
+
+
+
+
+
+
+
+
Class LetterHead
+
+
Inherits from frappe.model.document.Document
+
+
+
+
+
+
+
+
+
+
+ on_update
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ set_as_default
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ validate
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Linked In:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/print/print_format.html b/frappe/docs/current/models/print/print_format.html
new file mode 100644
index 0000000000..4423685754
--- /dev/null
+++ b/frappe/docs/current/models/print/print_format.html
@@ -0,0 +1,438 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
Table Name: tabPrint Format
+
+
+
+
+
Fields
+
+
+
+
+ Sr
+ Fieldname
+ Type
+ Label
+ Options
+
+
+
+
+
+ 1
+ doc_type
+
+ Link
+
+ DocType
+
+
+
+
+
+
+
+DocType
+
+
+
+
+
+
+
+ 2
+ disabled
+
+ Check
+
+ Disabled
+
+
+
+
+
+
+ 3
+ column_break_3
+
+ Column Break
+
+
+
+
+
+
+
+
+ 4
+ standard
+
+ Select
+
+ Standard
+
+
+
+ No
+Yes
+
+
+
+
+ 5
+ custom_format
+
+ Check
+
+ Custom Format
+
+
+
+
+
+
+ 6
+ section_break_6
+
+ Section Break
+
+
+
+
+
+
+
+
+ 7
+ print_format_type
+
+ Select
+
+ Print Format Type
+
+
+
+ Server
+Client
+
+
+
+
+ 8
+ html
+
+ Code
+
+ HTML
+
+
+
+ HTML
+
+
+
+
+ 9
+ section_break_9
+
+ Section Break
+
+
+
+
+
+
+
+
+ 10
+ edit_format
+
+ Button
+
+ Edit Format
+
+
+
+
+
+
+ 11
+ column_break_11
+
+ Column Break
+
+
+
+
+
+
+
+
+ 12
+ font
+
+ Select
+
+ Font
+
+
+
+ Default
+Arial
+Helvetica
+Verdana
+Monospace
+
+
+
+
+ 13
+ css_section
+
+ Section Break
+
+
+
+
+
+
+
+
+ 14
+ css
+
+ Code
+
+ Custom CSS
+
+
+
+
+
+
+ 15
+ custom_html_help
+
+ HTML
+
+ Custom HTML Help
+
+
+
+
+
+
+ 16
+ section_break_13
+
+ Section Break
+
+
+
+
+
+
+
+
+ 17
+ print_format_help
+
+ HTML
+
+ Print Format Help
+
+
+
+
+
+
+ 18
+ format_data
+
+ Code
+
+ Format Data
+
+
+
+
+
+
+ 19
+ print_format_builder
+
+ Check
+
+ Print Format Builder
+
+
+
+
+
+
+
+
+
+
+
Controller
+
frappe.print.doctype.print_format.print_format
+
+
+
+
+
+
+
+
Class PrintFormat
+
+
Inherits from frappe.model.document.Document
+
+
+
+
+
+
+
+
+
+
+ export_doc
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ extract_images
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ on_trash
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ on_update
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ validate
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.print.doctype.print_format.print_format.make_default
+
+
+
+
+ frappe.print.doctype.print_format.print_format.make_default
+ (name)
+
+
Set print format as default
+
+
+
+
+
+
+
+
+
Linked In:
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/print/print_settings.html b/frappe/docs/current/models/print/print_settings.html
new file mode 100644
index 0000000000..5b8a0d53c6
--- /dev/null
+++ b/frappe/docs/current/models/print/print_settings.html
@@ -0,0 +1,236 @@
+
+
+
+
+
+
+
+
+
Single
+
+
+
+
+
+
+
Fields
+
+
+
+
+ Sr
+ Fieldname
+ Type
+ Label
+ Options
+
+
+
+
+
+ 1
+ pdf_settings
+
+ Section Break
+
+ PDF Settings
+
+
+
+
+
+
+ 2
+ send_print_as_pdf
+
+ Check
+
+ Send Print as PDF
+
+ Send Email Print Attachments as PDF (Recommended)
+
+
+
+
+
+ 3
+ pdf_page_size
+
+ Select
+
+ PDF Page Size
+
+
+
+ A4
+Letter
+
+
+
+
+ 4
+ print_style_section
+
+ Section Break
+
+ Print Style
+
+
+
+
+
+
+ 5
+ print_style
+
+ Select
+
+ Print Style
+
+
+
+ Modern
+Classic
+Standard
+Monochrome
+
+
+
+
+ 6
+ font
+
+ Select
+
+ Font
+
+
+
+ Default
+Arial
+Helvetica
+Verdana
+Monospace
+
+
+
+
+ 7
+ font_size
+
+ Float
+
+ Font Size
+
+ In points. Default is 9.
+
+
+
+
+
+ 8
+ column_break_6
+
+ Column Break
+
+
+
+
+
+
+
+
+ 9
+ with_letterhead
+
+ Check
+
+ With Letterhead
+
+ Print with Letterhead, unless unchecked in a particular Document
+
+
+
+
+
+ 10
+ section_break_8
+
+ Section Break
+
+
+
+
+
+
+
+
+ 11
+ print_style_preview
+
+ HTML
+
+ Print Style Preview
+
+
+
+
+
+
+
+
+
+
+
Controller
+
frappe.print.doctype.print_settings.print_settings
+
+
+
+
+
+
+
+
Class PrintSettings
+
+
Inherits from frappe.model.document.Document
+
+
+
+
+
+
+
+
+
+
+ on_update
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/website/about_us_settings.html b/frappe/docs/current/models/website/about_us_settings.html
new file mode 100644
index 0000000000..11a861c6b4
--- /dev/null
+++ b/frappe/docs/current/models/website/about_us_settings.html
@@ -0,0 +1,233 @@
+
+
+
+
+
+
+
+
+
Single
+
+
+
+
+Settings for the About Us Page
+
+
Fields
+
+
+
+
+ Sr
+ Fieldname
+ Type
+ Label
+ Options
+
+
+
+
+
+ 1
+ help
+
+ HTML
+
+ Help
+
+
+
+
+
+
+ 2
+ company_introduction
+
+ Text Editor
+
+ Company Introduction
+
+ Introduce your company to the website visitor.
+
+
+
+
+
+ 3
+ sb0
+
+ Section Break
+
+ Org History
+
+
+
+
+
+
+ 4
+ company_history_heading
+
+ Data
+
+ Org History Heading
+
+ "Company History"
+
+
+
+
+
+ 5
+ company_history
+
+ Table
+
+ Org History
+
+
+
+
+
+
+
+Company History
+
+
+
+
+
+
+
+ 6
+ sb1
+
+ Section Break
+
+ Team Members
+
+
+
+
+
+
+ 7
+ team_members_heading
+
+ Data
+
+ Team Members Heading
+
+ "Team Members" or "Management"
+
+
+
+
+
+ 8
+ team_members
+
+ Table
+
+ Team Members
+
+
+
+
+
+
+
+About Us Team Member
+
+
+
+
+
+
+
+ 9
+ footer
+
+ Text Editor
+
+ Footer
+
+ More content for the bottom of the page.
+
+
+
+
+
+
+
+
+
+
Controller
+
frappe.website.doctype.about_us_settings.about_us_settings
+
+
+
+
+
+
+
+
Class AboutUsSettings
+
+
Inherits from frappe.model.document.Document
+
+
+
+
+
+
+
+
+
+
+ on_update
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.website.doctype.about_us_settings.about_us_settings.get_args
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/website/about_us_team_member.html b/frappe/docs/current/models/website/about_us_team_member.html
new file mode 100644
index 0000000000..74448d4f23
--- /dev/null
+++ b/frappe/docs/current/models/website/about_us_team_member.html
@@ -0,0 +1,99 @@
+
+
+
+
+
+
+
+
+
+
Child Table
+
+
+
Table Name: tabAbout Us Team Member
+
+
+
+
+
Fields
+
+
+
+
+ Sr
+ Fieldname
+ Type
+ Label
+ Options
+
+
+
+
+
+ 1
+ full_name
+
+ Data
+
+ Full Name
+
+
+
+
+
+
+ 2
+ image_link
+
+ Attach
+
+ Image Link
+
+
+
+
+
+
+ 3
+ bio
+
+ Small Text
+
+ Bio
+
+
+
+
+
+
+
+
+
+
+
+
Child Table Of
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/website/blog_category.html b/frappe/docs/current/models/website/blog_category.html
new file mode 100644
index 0000000000..c5cabbfeae
--- /dev/null
+++ b/frappe/docs/current/models/website/blog_category.html
@@ -0,0 +1,191 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
Table Name: tabBlog Category
+
+
+
+
+
Fields
+
+
+
+
+ Sr
+ Fieldname
+ Type
+ Label
+ Options
+
+
+
+
+
+ 1
+ category_name
+
+ Data
+
+ Category Name
+
+
+
+
+
+
+ 2
+ title
+
+ Data
+
+ Title
+
+
+
+
+
+
+ 3
+ published
+
+ Check
+
+ Published
+
+
+
+
+
+
+ 4
+ parent_website_route
+
+ Read Only
+
+ Parent Website Route
+
+
+
+
+
+
+ 5
+ page_name
+
+ Data
+
+ Page Name
+
+
+
+
+
+
+
+
+
+
+
Controller
+
frappe.website.doctype.blog_category.blog_category
+
+
+
+
+
+
+
+
Class BlogCategory
+
+
Inherits from frappe.website.website_generator.WebsiteGenerator
+
+
+
+
+
+
+
+
+
+
+ autoname
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ on_update
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ validate
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Linked In:
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/website/blog_post.html b/frappe/docs/current/models/website/blog_post.html
new file mode 100644
index 0000000000..16a87240cc
--- /dev/null
+++ b/frappe/docs/current/models/website/blog_post.html
@@ -0,0 +1,374 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
Table Name: tabBlog Post
+
+
+
+
+
Fields
+
+
+
+
+ Sr
+ Fieldname
+ Type
+ Label
+ Options
+
+
+
+
+
+ 1
+ title
+
+ Data
+
+ Title
+
+
+
+
+
+
+ 2
+ published_on
+
+ Date
+
+ Published On
+
+
+
+
+
+
+ 3
+ published
+
+ Check
+
+ Published
+
+
+
+
+
+
+ 4
+ column_break_3
+
+ Column Break
+
+
+
+
+
+
+
+
+ 5
+ blog_category
+
+ Link
+
+ Blog Category
+
+
+
+
+
+
+
+Blog Category
+
+
+
+
+
+
+
+ 6
+ blogger
+
+ Link
+
+ Blogger
+
+
+
+
+
+
+
+Blogger
+
+
+
+
+
+
+
+ 7
+ parent_website_route
+
+ Read Only
+
+ Parent Website Route
+
+
+
+
+
+
+ 8
+ section_break_5
+
+ Section Break
+
+
+
+
+
+
+
+
+ 9
+ blog_intro
+
+ Small Text
+
+ Blog Intro
+
+ Description for listing page, in plain text, only a couple of lines. (max 140 characters)
+
+
+
+
+
+ 10
+ content
+
+ Text Editor
+
+ Content
+
+
+
+
+
+
+ 11
+ page_name
+
+ Data
+
+ Page Name
+
+
+
+
+
+
+ 12
+ email_sent
+
+ Check
+
+ Email Sent
+
+
+
+
+
+
+
+
+
+
+
Controller
+
frappe.website.doctype.blog_post.blog_post
+
+
+
+
+
+
+
+
Class BlogPost
+
+
Inherits from frappe.website.website_generator.WebsiteGenerator
+
+
+
+
+
+
+
+
+
+
+ get_context
+ (self, context)
+
+
+
+
+
+
+
+
+
+
+
+ get_feed
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ on_update
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ validate
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.website.doctype.blog_post.blog_post.clear_blog_cache
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.website.doctype.blog_post.blog_post.get_blog_category
+ (page_name)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.website.doctype.blog_post.blog_post.get_blog_list
+ (doctype, txt=None, filters=None, limit_start=0, limit_page_length=20)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.website.doctype.blog_post.blog_post.get_children
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.website.doctype.blog_post.blog_post.get_list_context
+ (context=None)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/website/blog_settings.html b/frappe/docs/current/models/website/blog_settings.html
new file mode 100644
index 0000000000..5c30bd7f5f
--- /dev/null
+++ b/frappe/docs/current/models/website/blog_settings.html
@@ -0,0 +1,123 @@
+
+
+
+
+
+
+
+
+
Single
+
+
+
+
+Blog Settings
+
+
Fields
+
+
+
+
+ Sr
+ Fieldname
+ Type
+ Label
+ Options
+
+
+
+
+
+ 1
+ blog_title
+
+ Data
+
+ Blog Title
+
+
+
+
+
+
+ 2
+ blog_introduction
+
+ Small Text
+
+ Blog Introduction
+
+
+
+
+
+
+ 3
+ writers_introduction
+
+ Small Text
+
+ Writers Introduction
+
+
+
+
+
+
+
+
+
+
+
Controller
+
frappe.website.doctype.blog_settings.blog_settings
+
+
+
+
+
+
+
+
Class BlogSettings
+
+
Inherits from frappe.model.document.Document
+
+
+
+
+
+
+
+
+
+
+ on_update
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/website/blogger.html b/frappe/docs/current/models/website/blogger.html
new file mode 100644
index 0000000000..b0c97d2e08
--- /dev/null
+++ b/frappe/docs/current/models/website/blogger.html
@@ -0,0 +1,211 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
Table Name: tabBlogger
+
+
+User ID of a Blogger
+
+
Fields
+
+
+
+
+ Sr
+ Fieldname
+ Type
+ Label
+ Options
+
+
+
+
+
+ 1
+ disabled
+
+ Check
+
+ Disabled
+
+
+
+
+
+
+ 2
+ short_name
+
+ Data
+
+ Short Name
+
+ Will be used in url (usually first name).
+
+
+
+
+
+ 3
+ full_name
+
+ Data
+
+ Full Name
+
+
+
+
+
+
+ 4
+ user
+
+ Link
+
+ User
+
+
+
+
+
+
+
+User
+
+
+
+
+
+
+
+ 5
+ bio
+
+ Small Text
+
+ Bio
+
+
+
+
+
+
+ 6
+ avatar
+
+ Attach
+
+ Avatar
+
+
+
+
+
+
+ 7
+ posts
+
+ Int
+
+ Posts
+
+
+
+
+
+
+
+
+
+
+
Controller
+
frappe.website.doctype.blogger.blogger
+
+
+
+
+
+
+
+
Class Blogger
+
+
Inherits from frappe.model.document.Document
+
+
+
+
+
+
+
+
+
+
+ on_update
+ (self)
+
+
if user is set, then update all older blogs
+
+
+
+
+
+
+
+
+
+
+ validate
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Linked In:
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/website/company_history.html b/frappe/docs/current/models/website/company_history.html
new file mode 100644
index 0000000000..558a23e256
--- /dev/null
+++ b/frappe/docs/current/models/website/company_history.html
@@ -0,0 +1,87 @@
+
+
+
+
+
+
+
+
+
+
Child Table
+
+
+
Table Name: tabCompany History
+
+
+
+
+
Fields
+
+
+
+
+ Sr
+ Fieldname
+ Type
+ Label
+ Options
+
+
+
+
+
+ 1
+ year
+
+ Data
+
+ Year
+
+
+
+
+
+
+ 2
+ highlight
+
+ Text
+
+ Highlight
+
+
+
+
+
+
+
+
+
+
+
+
Child Table Of
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/website/contact_us_settings.html b/frappe/docs/current/models/website/contact_us_settings.html
new file mode 100644
index 0000000000..aecdf05f65
--- /dev/null
+++ b/frappe/docs/current/models/website/contact_us_settings.html
@@ -0,0 +1,247 @@
+
+
+
+
+
+
+
+
+
Single
+
+
+
+
+Settings for Contact Us Page
+
+
Fields
+
+
+
+
+ Sr
+ Fieldname
+ Type
+ Label
+ Options
+
+
+
+
+
+ 1
+ introduction_section
+
+ Section Break
+
+ Introduction
+
+
+
+
+
+
+ 2
+ forward_to_email
+
+ Data
+
+ Forward To Email Address
+
+ Send enquiries to this email address
+
+
+
+
+
+ 3
+ heading
+
+ Data
+
+ Heading
+
+ Default: "Contact Us"
+
+
+
+
+
+ 4
+ introduction
+
+ Text Editor
+
+ Introduction
+
+ Introductory information for the Contact Us Page
+
+
+
+
+
+ 5
+ query_options
+
+ Small Text
+
+ Query Options
+
+ Contact options, like "Sales Query, Support Query" etc each on a new line or separated by commas.
+
+
+
+
+
+ 6
+ address
+
+ Section Break
+
+ Address
+
+
+
+
+
+
+ 7
+ address_title
+
+ Data
+
+ Address Title
+
+
+
+
+
+
+ 8
+ address_line1
+
+ Data
+
+ Address Line 1
+
+
+
+
+
+
+ 9
+ address_line2
+
+ Data
+
+ Address Line 2
+
+
+
+
+
+
+ 10
+ city
+
+ Data
+
+ City
+
+
+
+
+
+
+ 11
+ state
+
+ Data
+
+ State
+
+
+
+
+
+
+ 12
+ pincode
+
+ Data
+
+ Pincode
+
+
+
+
+
+
+ 13
+ country
+
+ Data
+
+ Country
+
+
+
+
+
+
+
+
+
+
+
Controller
+
frappe.website.doctype.contact_us_settings.contact_us_settings
+
+
+
+
+
+
+
+
Class ContactUsSettings
+
+
Inherits from frappe.model.document.Document
+
+
+
+
+
+
+
+
+
+
+ on_update
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/website/index.html b/frappe/docs/current/models/website/index.html
new file mode 100644
index 0000000000..53876b1110
--- /dev/null
+++ b/frappe/docs/current/models/website/index.html
@@ -0,0 +1,19 @@
+
+
+
+
+
+
DocTypes for website
+
+{index}
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/website/index.txt b/frappe/docs/current/models/website/index.txt
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/frappe/docs/current/models/website/top_bar_item.html b/frappe/docs/current/models/website/top_bar_item.html
new file mode 100644
index 0000000000..053e1361b6
--- /dev/null
+++ b/frappe/docs/current/models/website/top_bar_item.html
@@ -0,0 +1,130 @@
+
+
+
+
+
+
+
+
+
+
Child Table
+
+
+
Table Name: tabTop Bar Item
+
+
+
+
+
Fields
+
+
+
+
+ Sr
+ Fieldname
+ Type
+ Label
+ Options
+
+
+
+
+
+ 1
+ label
+
+ Data
+
+ Label
+
+
+
+
+
+
+ 2
+ parent_label
+
+ Select
+
+ Parent Label
+
+ If you set this, this Item will come in a drop-down under the selected parent.
+
+
+
+
+
+ 3
+ url
+
+ Data
+
+ URL
+
+ Link to the page you want to open. Leave blank if you want to make it a group parent.
+
+
+
+
+
+ 4
+ target
+
+ Select
+
+ Target
+
+ Select target = "_blank" to open in a new page.
+
+
+
+target = "_blank"
+
+
+
+
+ 5
+ right
+
+ Check
+
+ Right
+
+ For top bar
+
+
+
+
+
+
+
+
+
+
+
Child Table Of
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/website/web_form.html b/frappe/docs/current/models/website/web_form.html
new file mode 100644
index 0000000000..d75443f074
--- /dev/null
+++ b/frappe/docs/current/models/website/web_form.html
@@ -0,0 +1,490 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
Table Name: tabWeb Form
+
+
+
+
+
Fields
+
+
+
+
+ Sr
+ Fieldname
+ Type
+ Label
+ Options
+
+
+
+
+
+ 1
+ title
+
+ Data
+
+ Title
+
+
+
+
+
+
+ 2
+ page_name
+
+ Data
+
+ Page Name
+
+ Website URL
+
+
+
+
+
+ 3
+ doc_type
+
+ Link
+
+ Select DocType
+
+
+
+
+
+
+
+DocType
+
+
+
+
+
+
+
+ 4
+ column_break_4
+
+ Column Break
+
+
+
+
+
+
+
+
+ 5
+ is_standard
+
+ Check
+
+ Is Standard
+
+
+
+
+
+
+ 6
+ published
+
+ Check
+
+ Published
+
+
+
+
+
+
+ 7
+ login_required
+
+ Check
+
+ Login Required
+
+
+
+
+
+
+ 8
+ allow_edit
+
+ Check
+
+ Allow Edit
+
+
+
+
+
+
+ 9
+ allow_multiple
+
+ Check
+
+ Allow Multiple
+
+
+
+
+
+
+ 10
+ allow_delete
+
+ Check
+
+ Allow Delete
+
+
+
+
+
+
+ 11
+ allow_comments
+
+ Check
+
+ Allow Comments
+
+
+
+
+
+
+ 12
+ fields
+
+ Section Break
+
+ Fields
+
+
+
+
+
+
+ 13
+ introduction_text
+
+ Text
+
+ Introduction
+
+
+
+
+
+
+ 14
+ web_form_fields
+
+ Table
+
+ Web Form Fields
+
+
+
+
+
+
+
+Web Form Field
+
+
+
+
+
+
+
+ 15
+ actions
+
+ Section Break
+
+ Actions
+
+
+
+
+
+
+ 16
+ success_message
+
+ Text
+
+ Success Message
+
+ Message to be displayed on successful completion
+
+
+
+
+
+ 17
+ success_url
+
+ Data
+
+ Success URL
+
+ Go to this url after completing the form.
+
+
+
+
+
+ 18
+ advanced
+
+ Section Break
+
+ Advanced
+
+
+
+
+
+
+ 19
+ web_page_link_text
+
+ Data
+
+ Web Page Link Text
+
+ Text to be displayed for Link to Web Page if this form has a web page. Link route will be automatically generated based on `page_name` and `parent_website_route`
+
+
+
+
+
+ 20
+ breadcrumbs
+
+ Small Text
+
+ Breadcrumbs
+
+ In JSON as [{"title":"Jobs", "name":"jobs"}]
+
+
+
+
+
+
+
+
+
+
Controller
+
frappe.website.doctype.web_form.web_form
+
+
+
+
+
+
+
+
Class WebForm
+
+
Inherits from frappe.website.website_generator.WebsiteGenerator
+
+
+
+
+
+
+
+
+
+
+ get_context
+ (self, context)
+
+
+
+
+
+
+
+
+
+
+
+ get_layout
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ get_parents
+ (self, context)
+
+
+
+
+
+
+
+
+
+
+
+ onload
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ use_meta_fields
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ validate
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.website.doctype.web_form.web_form.accept
+
+
+
+
+ frappe.website.doctype.web_form.web_form.accept
+ ()
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.website.doctype.web_form.web_form.delete
+
+
+
+
+ frappe.website.doctype.web_form.web_form.delete
+ (web_form, name)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.website.doctype.web_form.web_form.get_web_form_list
+ (doctype, txt, filters, limit_start, limit_page_length=20)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.website.doctype.web_form.web_form.has_web_form_permission
+ (doctype, name, ptype=read)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/website/web_form_field.html b/frappe/docs/current/models/website/web_form_field.html
new file mode 100644
index 0000000000..7a7ffc4f90
--- /dev/null
+++ b/frappe/docs/current/models/website/web_form_field.html
@@ -0,0 +1,219 @@
+
+
+
+
+
+
+
+
+
+
Child Table
+
+
+
Table Name: tabWeb Form Field
+
+
+
+
+
Fields
+
+
+
+
+ Sr
+ Fieldname
+ Type
+ Label
+ Options
+
+
+
+
+
+ 1
+ fieldname
+
+ Select
+
+ Fieldname
+
+
+
+
+
+
+ 2
+ fieldtype
+
+ Select
+
+ Fieldtype
+
+
+
+ Attach
+Check
+Data
+Date
+Datetime
+HTML
+Link
+Select
+Text
+Section Break
+Column Break
+
+
+
+
+ 3
+ label
+
+ Data
+
+ Label
+
+
+
+
+
+
+ 4
+ reqd
+
+ Check
+
+ Mandatory
+
+
+
+
+
+
+ 5
+ read_only
+
+ Check
+
+ Read Only
+
+
+
+
+
+
+ 6
+ hidden
+
+ Check
+
+ Hidden
+
+
+
+
+
+
+ 7
+ column_break_4
+
+ Column Break
+
+
+
+
+
+
+
+
+ 8
+ options
+
+ Text
+
+ Options
+
+
+
+
+
+
+ 9
+ section_break_6
+
+ Section Break
+
+
+
+
+
+
+
+
+ 10
+ description
+
+ Text
+
+ Description
+
+
+
+
+
+
+ 11
+ column_break_8
+
+ Column Break
+
+
+
+
+
+
+
+
+ 12
+ default
+
+ Data
+
+ Default
+
+
+
+
+
+
+
+
+
+
+
+
Child Table Of
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/website/web_page.html b/frappe/docs/current/models/website/web_page.html
new file mode 100644
index 0000000000..d7acc0e721
--- /dev/null
+++ b/frappe/docs/current/models/website/web_page.html
@@ -0,0 +1,577 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
Table Name: tabWeb Page
+
+
+Page to show on the website
+
+
+
Fields
+
+
+
+
+ Sr
+ Fieldname
+ Type
+ Label
+ Options
+
+
+
+
+
+ 1
+ section_title
+
+ Section Break
+
+ Title
+
+
+
+
+
+
+ 2
+ title
+
+ Data
+
+ Title
+
+ Title / headline of your page
+
+
+
+
+
+ 3
+ show_title
+
+ Check
+
+ Show Title
+
+
+
+
+
+
+ 4
+ slideshow
+
+ Link
+
+ Slideshow
+
+ Begin this page with a slideshow of images
+
+
+
+
+
+
+Website Slideshow
+
+
+
+
+
+
+
+ 5
+ cb1
+
+ Column Break
+
+
+
+
+
+
+
+
+ 6
+ page_name
+
+ Data
+
+ Page Name
+
+ Page url name (auto-generated)
+
+
+
+
+
+ 7
+ published
+
+ Check
+
+ Published
+
+
+
+
+
+
+ 8
+ sb1
+
+ Section Break
+
+ Content
+
+ Page content
+
+
+
+
+
+ 9
+ main_section
+
+ Text Editor
+
+ Main Section
+
+ Content in markdown format that appears on the main side of your page
+
+
+
+
+
+ 10
+ fold_10
+
+ Fold
+
+
+
+
+
+
+
+
+ 11
+ custom_javascript
+
+ Section Break
+
+ Custom Javascript
+
+
+
+
+
+
+ 12
+ insert_code
+
+ Check
+
+ Insert Code
+
+ Add code as <script>
+
+
+
+
+
+ 13
+ javascript
+
+ Code
+
+ Javascript
+
+
+
+ Javascript
+
+
+
+
+ 14
+ custom_css
+
+ Section Break
+
+ Custom CSS
+
+
+
+
+
+
+ 15
+ insert_style
+
+ Check
+
+ Insert Style
+
+
+
+
+
+
+ 16
+ css
+
+ Code
+
+ CSS
+
+
+
+ CSS
+
+
+
+
+ 17
+ section_break_17
+
+ Section Break
+
+
+
+
+
+
+
+
+ 18
+ enable_comments
+
+ Check
+
+ Enable Comments
+
+
+
+
+
+
+ 19
+ text_align
+
+ Select
+
+ Text Align
+
+
+
+ Left
+Center
+Right
+
+
+
+
+ 20
+ column_break_20
+
+ Column Break
+
+
+
+
+
+
+
+
+ 21
+ parent_web_page
+
+ Link
+
+ Parent Web Page
+
+
+
+
+
+
+
+Web Page
+
+
+
+
+
+
+
+ 22
+ parent_website_route
+
+ Read Only
+
+ Parent Website Route
+
+
+
+
+
+
+ 23
+ idx
+
+ Int
+
+ Priority
+
+ 0 is highest
+
+
+
+
+
+ 24
+ template_path
+
+ Small Text
+
+ Template Path
+
+
+
+
+
+
+ 25
+ sb2
+
+ Section Break
+
+
+
+
+
+
+
+
+ 26
+ description
+
+ Small Text
+
+ Description
+
+ Description for search engine optimization.
+
+
+
+
+
+ 27
+ header
+
+ Text
+
+ Header
+
+ HTML for header section. Optional
+
+
+
+
+
+
+
+
+
+
Controller
+
frappe.website.doctype.web_page.web_page
+
+
+
+
+
+
+
+
Class WebPage
+
+
Inherits from frappe.website.website_generator.WebsiteGenerator
+
+
+
+
+
+
+
+
+
+
+ check_for_redirect
+ (self, context)
+
+
+
+
+
+
+
+
+
+
+
+ get_context
+ (self, context)
+
+
+
+
+
+
+
+
+
+
+
+ get_dynamic_context
+ (self, context)
+
+
update context from .py and load sidebar from _sidebar.json if either exists
+
+
+
+
+
+
+
+
+
+
+ get_feed
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ get_static_content
+ (self, context)
+
+
+
+
+
+
+
+
+
+
+
+ render_dynamic
+ (self, context)
+
+
+
+
+
+
+
+
+
+
+
+ set_metatags
+ (self, context)
+
+
+
+
+
+
+
+
+
+
+
+ validate
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.website.doctype.web_page.web_page.check_broken_links
+ ()
+
+
+
+
+
+
+
+
+
+
Linked In:
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/website/website_script.html b/frappe/docs/current/models/website/website_script.html
new file mode 100644
index 0000000000..5761f40cbe
--- /dev/null
+++ b/frappe/docs/current/models/website/website_script.html
@@ -0,0 +1,101 @@
+
+
+
+
+
+
+
+
+
Single
+
+
+
+
+Script to attach to all web pages.
+
+
Fields
+
+
+
+
+ Sr
+ Fieldname
+ Type
+ Label
+ Options
+
+
+
+
+
+ 1
+ javascript
+
+ Code
+
+ Javascript
+
+
+
+ Javascript
+
+
+
+
+
+
+
+
+
Controller
+
frappe.website.doctype.website_script.website_script
+
+
+
+
+
+
+
+
Class WebsiteScript
+
+
Inherits from frappe.model.document.Document
+
+
+
+
+
+
+
+
+
+
+ on_update
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/website/website_settings.html b/frappe/docs/current/models/website/website_settings.html
new file mode 100644
index 0000000000..b3fa19e110
--- /dev/null
+++ b/frappe/docs/current/models/website/website_settings.html
@@ -0,0 +1,698 @@
+
+
+
+
+
+
+
+
+
Single
+
+
+
+
+
+
+
Fields
+
+
+
+
+ Sr
+ Fieldname
+ Type
+ Label
+ Options
+
+
+
+
+
+ 1
+ sb0
+
+ Section Break
+
+ Landing Page
+
+
+
+
+
+
+ 2
+ home_page
+
+ Data
+
+ Home Page
+
+ Link that is the website home page. Standard Links (index, login, products, blog, about, contact)
+
+
+
+
+
+ 3
+ home_page_is_products
+
+ Check
+
+ Home Page is Products
+
+ If checked, the Home page will be the default Item Group for the website.
+
+
+
+
+
+ 4
+ cb4
+
+ Column Break
+
+
+
+
+
+
+
+
+ 5
+ title_prefix
+
+ Data
+
+ Title Prefix
+
+ Show title in browser window as "Prefix - title"
+
+
+
+
+
+ 6
+ section_break_6
+
+ Section Break
+
+
+
+
+
+
+
+
+ 7
+ website_theme
+
+ Link
+
+ Website Theme
+
+
+
+
+
+
+
+Website Theme
+
+
+
+
+
+
+
+ 8
+ website_theme_image
+
+ Image
+
+ Website Theme Image
+
+
+
+ website_theme_image_link
+
+
+
+
+ 9
+ website_theme_image_link
+
+ Small Text
+
+ Website Theme Image Link
+
+
+
+
+
+
+ 10
+ banner
+
+ Section Break
+
+ Banner
+
+ Add a banner to the site. (small banners are usually good)
+
+
+
+
+
+ 11
+ banner_image
+
+ Attach Image
+
+ Banner Image
+
+ Select an image of approx width 150px with a transparent background for best results.
+
+
+
+
+
+ 12
+ set_banner_from_image
+
+ Button
+
+ Set Banner from Image
+
+
+
+
+
+
+ 13
+ column_break_14
+
+ Column Break
+
+
+
+
+
+
+
+
+ 14
+ banner_html
+
+ Small Text
+
+ Banner HTML
+
+ Banner is above the Top Menu Bar.
+
+
+
+
+
+ 15
+ top_bar
+
+ Section Break
+
+ Top Bar
+
+ Menu items in the Top Bar. For setting the color of the Top Bar, go to selected Website Theme.
+
+
+
+
+
+ 16
+ brand_html
+
+ Small Text
+
+ Brand HTML
+
+ Brand is what appears on the top-left of the toolbar. If it is an image, make sure it
+has a transparent background and use the <img /> tag. Keep size as 200px x 30px
+
+
+
+
+
+ 17
+ top_bar_items
+
+ Table
+
+ Top Bar Items
+
+
+
+
+
+
+
+Top Bar Item
+
+
+
+
+
+
+
+ 18
+ sidebar
+
+ Section Break
+
+ Sidebar
+
+ Sidebar Links for Home Page only
+
+
+
+
+
+ 19
+ sidebar_items
+
+ Table
+
+ Sidebar Items
+
+
+
+
+
+
+
+Top Bar Item
+
+
+
+
+
+
+
+ 20
+ footer
+
+ Section Break
+
+ Footer
+
+
+
+
+
+
+ 21
+ copyright
+
+ Data
+
+ Copyright
+
+
+
+
+
+
+ 22
+ address
+
+ Text Editor
+
+ Address
+
+ Address and other legal information you may want to put in the footer.
+
+
+
+
+
+ 23
+ footer_items
+
+ Table
+
+ Footer Items
+
+
+
+
+
+
+
+Top Bar Item
+
+
+
+
+
+
+
+ 24
+ hide_footer_signup
+
+ Check
+
+ Hide Footer Signup
+
+
+
+
+
+
+ 25
+ integrations
+
+ Section Break
+
+ Integrations
+
+
+
+
+
+
+ 26
+ google_analytics_id
+
+ Data
+
+ Google Analytics ID
+
+ Add Google Analytics ID: eg. UA-89XXX57-1. Please search help on Google Analytics for more information.
+
+
+
+
+
+ 27
+ column_break_17
+
+ Column Break
+
+
+
+
+
+
+
+
+ 28
+ google_plus_one
+
+ Check
+
+ Google Plus One
+
+
+
+
+
+
+ 29
+ facebook_share
+
+ Check
+
+ Facebook Share
+
+
+
+
+
+
+ 30
+ linked_in_share
+
+ Check
+
+ Linked In Share
+
+
+
+
+
+
+ 31
+ twitter_share
+
+ Check
+
+ Twitter Share
+
+
+
+
+
+
+ 32
+ twitter_share_via
+
+ Data
+
+ Twitter Share via
+
+ Tweet will be shared via your user account (if specified)
+
+
+
+
+
+ 33
+ misc_section
+
+ Section Break
+
+ More Information
+
+
+
+
+
+
+ 34
+ favicon
+
+ Attach
+
+ FavIcon
+
+ An icon file with .ico extension. Should be 16 x 16 px. Generated using a favicon generator. [favicon-generator.org]
+
+
+
+
+
+ 35
+ subdomain
+
+ Text
+
+ Subdomain
+
+ Sub-domain provided by erpnext.com
+
+
+
+
+
+ 36
+ column_break_28
+
+ Column Break
+
+
+
+
+
+
+
+
+ 37
+ disable_signup
+
+ Check
+
+ Disable Signup
+
+ Disable Customer Signup link in Login page
+
+
+
+
+
+ 38
+ section_break_38
+
+ Section Break
+
+
+
+
+
+
+
+
+ 39
+ head_html
+
+ Code
+
+ <head> HTML
+
+ Added HTML in the <head> section of the web page, primarily used for website verification and SEO
+
+
+ HTML
+
+
+
+
+
+
+
+
+
Controller
+
frappe.website.doctype.website_settings.website_settings
+
+
+
+
+
+
+
+
Class WebsiteSettings
+
+
Inherits from frappe.model.document.Document
+
+
+
+
+
+
+
+
+
+
+ clear_cache
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ on_update
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ validate
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ validate_footer_items
+ (self)
+
+
clear parent label in footer
+
+
+
+
+
+
+
+
+
+
+ validate_home_page
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ validate_top_bar_items
+ (self)
+
+
validate url in top bar items
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.website.doctype.website_settings.website_settings.get_website_settings
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/website/website_slideshow.html b/frappe/docs/current/models/website/website_slideshow.html
new file mode 100644
index 0000000000..2045dc362d
--- /dev/null
+++ b/frappe/docs/current/models/website/website_slideshow.html
@@ -0,0 +1,182 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
Table Name: tabWebsite Slideshow
+
+
+Slideshow like display for the website
+
+
Fields
+
+
+
+
+ Sr
+ Fieldname
+ Type
+ Label
+ Options
+
+
+
+
+
+ 1
+ slideshow_name
+
+ Data
+
+ Slideshow Name
+
+
+
+
+
+
+ 2
+ sb0
+
+ Section Break
+
+
+
+ Note: For best results, images must be of the same size and width must be greater than height.
+
+
+
+
+
+ 3
+ slideshow_items
+
+ Table
+
+ Slideshow Items
+
+
+
+
+
+
+
+Website Slideshow Item
+
+
+
+
+
+
+
+ 4
+ header
+
+ Text Editor
+
+ Header
+
+ This goes above the slideshow.
+
+
+
+
+
+
+
+
+
+
Controller
+
frappe.website.doctype.website_slideshow.website_slideshow
+
+
+
+
+
+
+
+
Class WebsiteSlideshow
+
+
Inherits from frappe.model.document.Document
+
+
+
+
+
+
+
+
+
+
+ on_update
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.website.doctype.website_slideshow.website_slideshow.get_slideshow
+ (doc)
+
+
+
+
+
+
+
+
+
+
Linked In:
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/website/website_slideshow_item.html b/frappe/docs/current/models/website/website_slideshow_item.html
new file mode 100644
index 0000000000..8ab9fdb8ef
--- /dev/null
+++ b/frappe/docs/current/models/website/website_slideshow_item.html
@@ -0,0 +1,99 @@
+
+
+
+
+
+
+
+
+
+
Child Table
+
+
+
Table Name: tabWebsite Slideshow Item
+
+
+
+
+
Fields
+
+
+
+
+ Sr
+ Fieldname
+ Type
+ Label
+ Options
+
+
+
+
+
+ 1
+ image
+
+ Attach
+
+ Image
+
+
+
+
+
+
+ 2
+ heading
+
+ Data
+
+ Heading
+
+
+
+
+
+
+ 3
+ description
+
+ Text
+
+ Description
+
+
+
+
+
+
+
+
+
+
+
+
Child Table Of
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/website/website_theme.html b/frappe/docs/current/models/website/website_theme.html
new file mode 100644
index 0000000000..ddbf8fb825
--- /dev/null
+++ b/frappe/docs/current/models/website/website_theme.html
@@ -0,0 +1,629 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
Table Name: tabWebsite Theme
+
+
+
+
+
Fields
+
+
+
+
+ Sr
+ Fieldname
+ Type
+ Label
+ Options
+
+
+
+
+
+ 1
+ theme
+
+ Data
+
+ Theme
+
+
+
+
+
+
+ 2
+ module
+
+ Link
+
+ Module
+
+
+
+
+
+
+
+Module Def
+
+
+
+
+
+
+
+ 3
+ apply_style
+
+ Check
+
+ Apply Style
+
+ This must be checked if the below style settings are applicable
+
+
+
+
+
+ 4
+ custom
+
+ Check
+
+ Custom?
+
+
+
+
+
+
+ 5
+ column_break_2
+
+ Column Break
+
+
+
+
+
+
+
+
+ 6
+ bootstrap
+
+ Small Text
+
+ Link to Bootstrap CSS
+
+ Link to your Bootstrap theme
+
+
+
+
+
+ 7
+ section_break_14
+
+ Section Break
+
+
+
+
+
+
+
+
+ 8
+ font_size
+
+ Select
+
+ Font Size
+
+
+
+
+12px
+13px
+14px
+15px
+16px
+17px
+18px
+
+
+
+
+ 9
+ text_webfont
+
+ Data
+
+ Google Font (Text)
+
+ Add the name of a "Google Web Font" e.g. "Open Sans"
+
+
+
+
+
+ 10
+ heading_webfont
+
+ Data
+
+ Google Font (Heading)
+
+ Add the name of a "Google Web Font" e.g. "Open Sans"
+
+
+
+
+
+ 11
+ column_break_18
+
+ Column Break
+
+
+
+
+
+
+
+
+ 12
+ text_color
+
+ Data
+
+ Text Color
+
+
+
+
+
+
+ 13
+ link_color
+
+ Data
+
+ Link Color
+
+
+
+
+
+
+ 14
+ heading_style
+
+ Select
+
+ Heading Style
+
+
+
+
+UPPERCASE
+Title Case
+lowercase
+
+
+
+
+ 15
+ section_break_8
+
+ Section Break
+
+
+
+
+
+
+
+
+ 16
+ top_bar_color
+
+ Data
+
+ Top Bar Color
+
+
+
+
+
+
+ 17
+ top_bar_text_color
+
+ Data
+
+ Top Bar Text Color
+
+
+
+
+
+
+ 18
+ no_sidebar
+
+ Check
+
+ Hide Sidebar
+
+
+
+
+
+
+ 19
+ column_break_11
+
+ Column Break
+
+
+
+
+
+
+
+
+ 20
+ footer_color
+
+ Data
+
+ Footer Color
+
+
+
+
+
+
+ 21
+ footer_text_color
+
+ Data
+
+ Footer Text Color
+
+
+
+
+
+
+ 22
+ section_break_4
+
+ Section Break
+
+
+
+
+
+
+
+
+ 23
+ background_color
+
+ Data
+
+ Background Color
+
+
+
+
+
+
+ 24
+ column_break_6
+
+ Column Break
+
+
+
+
+
+
+
+
+ 25
+ background_image
+
+ Attach Image
+
+ Background Image
+
+ If image is selected, color will be ignored.
+
+
+
+
+
+ 26
+ section_break_21
+
+ Section Break
+
+
+
+
+
+
+
+
+ 27
+ css
+
+ Code
+
+ Style using CSS
+
+
+
+
+
+
+ 28
+ js
+
+ Code
+
+ JavaScript
+
+
+
+
+
+
+
+
+
+
+
Controller
+
frappe.website.doctype.website_theme.website_theme
+
+
+
+
+
+
+
+
Class WebsiteTheme
+
+
Inherits from frappe.model.document.Document
+
+
+
+
+
+
+
+
+
+
+ clear_cache_if_current_theme
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ export_doc
+ (self)
+
+
Export to standard folder [module]/website_theme/[name]/[name].json.
+
+
+
+
+
+
+
+
+
+
+ is_standard_and_not_valid_user
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ on_trash
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ on_update
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ use_theme
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ validate
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ validate_colors
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ validate_if_customizable
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.website.doctype.website_theme.website_theme.add_website_theme
+ (context)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frappe.website.doctype.website_theme.website_theme.get_active_theme
+ ()
+
+
+
+
+
+
+
+
+
+
Public API
+ /api/method/frappe.website.doctype.website_theme.website_theme.use_theme
+
+
+
+
+ frappe.website.doctype.website_theme.website_theme.use_theme
+ (theme)
+
+
+
+
+
+
+
+
+
+
Linked In:
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/workflow/index.html b/frappe/docs/current/models/workflow/index.html
new file mode 100644
index 0000000000..58a9cb74b6
--- /dev/null
+++ b/frappe/docs/current/models/workflow/index.html
@@ -0,0 +1,19 @@
+
+
+
+
+
+
DocTypes for workflow
+
+{index}
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/workflow/index.txt b/frappe/docs/current/models/workflow/index.txt
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/frappe/docs/current/models/workflow/workflow.html b/frappe/docs/current/models/workflow/workflow.html
new file mode 100644
index 0000000000..33f8599169
--- /dev/null
+++ b/frappe/docs/current/models/workflow/workflow.html
@@ -0,0 +1,289 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
Table Name: tabWorkflow
+
+
+Defines workflow states and rules for a document.
+
+
Fields
+
+
+
+
+ Sr
+ Fieldname
+ Type
+ Label
+ Options
+
+
+
+
+
+ 1
+ workflow_name
+
+ Data
+
+ Workflow Name
+
+
+
+
+
+
+ 2
+ document_type
+
+ Link
+
+ Document Type
+
+ DocType on which this Workflow is applicable.
+
+
+
+
+
+
+DocType
+
+
+
+
+
+
+
+ 3
+ is_active
+
+ Check
+
+ Is Active
+
+ If checked, all other workflows become inactive.
+
+
+
+
+
+ 4
+ states_head
+
+ Section Break
+
+ States
+
+ Different "States" this document can exist in. Like "Open", "Pending Approval" etc.
+
+
+
+
+
+ 5
+ states
+
+ Table
+
+ Document States
+
+ All possible Workflow States and roles of the workflow. Docstatus Options: 0 is"Saved", 1 is "Submitted" and 2 is "Cancelled"
+
+
+
+
+
+
+Workflow Document State
+
+
+
+
+
+
+
+ 6
+ transition_rules
+
+ Section Break
+
+ Transition Rules
+
+ Rules for how states are transitions, like next state and which role is allowed to change state etc.
+
+
+
+
+
+ 7
+ transitions
+
+ Table
+
+ Transitions
+
+ Rules defining transition of state in the workflow.
+
+
+
+
+
+
+Workflow Transition
+
+
+
+
+
+
+
+ 8
+ workflow_state_field
+
+ Data
+
+ Workflow State Field
+
+ Field that represents the Workflow State of the transaction (if field is not present, a new hidden Custom Field will be created)
+
+
+
+
+
+
+
+
+
+
Controller
+
frappe.workflow.doctype.workflow.workflow
+
+
+
+
+
+
+
+
Class Workflow
+
+
Inherits from frappe.model.document.Document
+
+
+
+
+
+
+
+
+
+
+ create_custom_field_for_workflow_state
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ on_update
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ set_active
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ update_default_workflow_status
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ validate
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+ validate_docstatus
+ (self)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/workflow/workflow_action.html b/frappe/docs/current/models/workflow/workflow_action.html
new file mode 100644
index 0000000000..9b49e952aa
--- /dev/null
+++ b/frappe/docs/current/models/workflow/workflow_action.html
@@ -0,0 +1,101 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
Table Name: tabWorkflow Action
+
+
+Workflow Action Master
+
+
Fields
+
+
+
+
+ Sr
+ Fieldname
+ Type
+ Label
+ Options
+
+
+
+
+
+ 1
+ workflow_action_name
+
+ Data
+
+ Workflow Action Name
+
+
+
+
+
+
+
+
+
+
+
Controller
+
frappe.workflow.doctype.workflow_action.workflow_action
+
+
+
+
+
+
+
+
Class WorkflowAction
+
+
Inherits from frappe.model.document.Document
+
+
+
+
+
+
+
+
+
+
+
+
+
Linked In:
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/workflow/workflow_document_state.html b/frappe/docs/current/models/workflow/workflow_document_state.html
new file mode 100644
index 0000000000..01b8bb7857
--- /dev/null
+++ b/frappe/docs/current/models/workflow/workflow_document_state.html
@@ -0,0 +1,158 @@
+
+
+
+
+
+
+
+
+
+
Child Table
+
+
+
Table Name: tabWorkflow Document State
+
+
+Represents the states allowed in one document and role assigned to change the state.
+
+
Fields
+
+
+
+
+ Sr
+ Fieldname
+ Type
+ Label
+ Options
+
+
+
+
+
+ 1
+ state
+
+ Link
+
+ State
+
+
+
+
+
+
+
+Workflow State
+
+
+
+
+
+
+
+ 2
+ doc_status
+
+ Select
+
+ Doc Status
+
+ 0 - Draft; 1 - Submitted; 2 - Cancelled
+
+
+ 0
+1
+2
+
+
+
+
+ 3
+ update_field
+
+ Select
+
+ Update Field
+
+
+
+
+
+
+ 4
+ update_value
+
+ Data
+
+ Update Value
+
+
+
+
+
+
+ 5
+ allow_edit
+
+ Link
+
+ Only Allow Edit For
+
+
+
+
+
+
+
+Role
+
+
+
+
+
+
+
+ 6
+ message
+
+ Text
+
+ Message
+
+
+
+
+
+
+
+
+
+
+
+
Child Table Of
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/workflow/workflow_state.html b/frappe/docs/current/models/workflow/workflow_state.html
new file mode 100644
index 0000000000..344578dd58
--- /dev/null
+++ b/frappe/docs/current/models/workflow/workflow_state.html
@@ -0,0 +1,286 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
Table Name: tabWorkflow State
+
+
+Workflow state represents the current state of a document.
+
+
Fields
+
+
+
+
+ Sr
+ Fieldname
+ Type
+ Label
+ Options
+
+
+
+
+
+ 1
+ workflow_state_name
+
+ Data
+
+ State
+
+
+
+
+
+
+ 2
+ icon
+
+ Select
+
+ Icon
+
+ Icon will appear on the button
+
+
+
+glass
+music
+search
+envelope
+heart
+star
+star-empty
+user
+film
+th-large
+th
+th-list
+ok
+remove
+zoom-in
+zoom-out
+off
+signal
+cog
+trash
+home
+file
+time
+road
+download-alt
+download
+upload
+inbox
+play-circle
+repeat
+refresh
+list-alt
+lock
+flag
+headphones
+volume-off
+volume-down
+volume-up
+qrcode
+barcode
+tag
+tags
+book
+bookmark
+print
+camera
+font
+bold
+italic
+text-height
+text-width
+align-left
+align-center
+align-right
+align-justify
+list
+indent-left
+indent-right
+facetime-video
+picture
+pencil
+map-marker
+adjust
+tint
+edit
+share
+check
+move
+step-backward
+fast-backward
+backward
+play
+pause
+stop
+forward
+fast-forward
+step-forward
+eject
+chevron-left
+chevron-right
+plus-sign
+minus-sign
+remove-sign
+ok-sign
+question-sign
+info-sign
+screenshot
+remove-circle
+ok-circle
+ban-circle
+arrow-left
+arrow-right
+arrow-up
+arrow-down
+share-alt
+resize-full
+resize-small
+plus
+minus
+asterisk
+exclamation-sign
+gift
+leaf
+fire
+eye-open
+eye-close
+warning-sign
+plane
+calendar
+random
+comment
+magnet
+chevron-up
+chevron-down
+retweet
+shopping-cart
+folder-close
+folder-open
+resize-vertical
+resize-horizontal
+hdd
+bullhorn
+bell
+certificate
+thumbs-up
+thumbs-down
+hand-right
+hand-left
+hand-up
+hand-down
+circle-arrow-right
+circle-arrow-left
+circle-arrow-up
+circle-arrow-down
+globe
+wrench
+tasks
+filter
+briefcase
+fullscreen
+
+
+
+
+ 3
+ style
+
+ Select
+
+ Style
+
+ Style represents the button color: Success - Green, Danger - Red, Inverse - Black, Primary - Dark Blue, Info - Light Blue, Warning - Orange
+
+
+
+Primary
+Info
+Success
+Warning
+Danger
+Inverse
+
+
+
+
+
+
+
+
+
Controller
+
frappe.workflow.doctype.workflow_state.workflow_state
+
+
+
+
+
+
+
+
Class WorkflowState
+
+
Inherits from frappe.model.document.Document
+
+
+
+
+
+
+
+
+
+
+
+
+
Linked In:
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/current/models/workflow/workflow_transition.html b/frappe/docs/current/models/workflow/workflow_transition.html
new file mode 100644
index 0000000000..51aca629fe
--- /dev/null
+++ b/frappe/docs/current/models/workflow/workflow_transition.html
@@ -0,0 +1,147 @@
+
+
+
+
+
+
+
+
+
+
Child Table
+
+
+
Table Name: tabWorkflow Transition
+
+
+Defines actions on states and the next step and allowed roles.
+
+
Fields
+
+
+
+
+ Sr
+ Fieldname
+ Type
+ Label
+ Options
+
+
+
+
+
+ 1
+ state
+
+ Link
+
+ State
+
+
+
+
+
+
+
+Workflow State
+
+
+
+
+
+
+
+ 2
+ action
+
+ Link
+
+ Action
+
+
+
+
+
+
+
+Workflow Action
+
+
+
+
+
+
+
+ 3
+ next_state
+
+ Link
+
+ Next State
+
+
+
+
+
+
+
+Workflow State
+
+
+
+
+
+
+
+ 4
+ allowed
+
+ Link
+
+ Allowed
+
+
+
+
+
+
+
+Role
+
+
+
+
+
+
+
+
+
+
+
+
+
Child Table Of
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/index.html b/frappe/docs/index.html
new file mode 100644
index 0000000000..8b1e6eb3d8
--- /dev/null
+++ b/frappe/docs/index.html
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+
+
+
+
Superhero Web Framework
+
Build extensions to ERPNext or make your own app
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Frappe is a full stack web application framework written in Python,
+Javascript, HTML/CSS with MySQL as the backend. It was built for ERPNext
+but is pretty generic and can be used to build database driven apps.
+
+
The key differece in Frappe compared to other frameworks is that Frappe
+is that meta-data is also treated as data and is used to build front-ends
+very easily. Frappe comes with a full blown admin UI called the Desk
+that handles forms, navigation, lists, menus, permissions, file attachment
+and much more out of the box.
+
+
Frappe also has a plug-in architecture that can be used to build plugins
+to ERPNext.
+
+
Frappe Framework was designed to build ERPNext , open source
+ERP for managing small and medium sized businesses.
+
+
Get started with the Tutorial
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/index.txt b/frappe/docs/index.txt
new file mode 100644
index 0000000000..4bdfdc4ac8
--- /dev/null
+++ b/frappe/docs/index.txt
@@ -0,0 +1,6 @@
+assets
+user
+contents
+current
+install
+license
diff --git a/frappe/docs/install.md b/frappe/docs/install.md
new file mode 100644
index 0000000000..7350f8f4ab
--- /dev/null
+++ b/frappe/docs/install.md
@@ -0,0 +1,30 @@
+
+
+# Installation
+
+Frappe Framework is based on the
Frappe Framework , a full stack web framework based on Python, MariaDB, Redis, Node.
+
+To intall Frappe Framework, you will have to install the
Frappe Bench , the command-line, package manager and site manager for Frappe Framework. For more details, read the Bench README.
+
+After you have installed Frappe Bench, go to you bench folder, which is `frappe.bench` by default and setup **frappe**.
+
+ bench get-app frappe {{ source_link }}
+
+Then create a new site to install the app.
+
+ bench new-site mysite
+
+This will create a new folder in your `/sites` directory and create a new database for this site.
+
+Next, install frappe in this site
+
+ bench --site mysite install-app frappe
+
+To run this locally, run
+
+ bench start
+
+Fire up your browser and go to http://localhost:8000 and you should see the login screen. Login as **Administrator** and **admin** (or the password you set at the time of `new-site`) and you are set.
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/license.html b/frappe/docs/license.html
new file mode 100644
index 0000000000..c462cdba43
--- /dev/null
+++ b/frappe/docs/license.html
@@ -0,0 +1,16 @@
+
+
+
MIT
+
+
The MIT License (MIT)
+
+
Copyright (c) 2015 Frappe Technologies Pvt. Ltd.
+
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/user/guides/.txt b/frappe/docs/user/guides/.txt
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/frappe/docs/user/guides/app-development/adding-module-icons-on-desktop.md b/frappe/docs/user/guides/app-development/adding-module-icons-on-desktop.md
new file mode 100644
index 0000000000..e6e0156bf6
--- /dev/null
+++ b/frappe/docs/user/guides/app-development/adding-module-icons-on-desktop.md
@@ -0,0 +1,34 @@
+To create a module icon for a Page, List or Module, you will have to edit the `config/desktop.py` file in your app.
+
+In this file you will have to write the `get_data` method that will return a dict object with the module icon parameters
+
+### Example 1: Module Icon
+
+ def get_data():
+ return {
+ "Accounts": {
+ "color": "#3498db",
+ "icon": "octicon octicon-repo",
+ "type": "module"
+ },
+ }
+
+### Example 2: List Icon
+
+ def get_data():
+ return {
+ "To Do": {
+ "color": "#f1c40f",
+ "icon": "icon-check",
+ "icon": "octicon octicon-check",
+ "label": _("To Do"),
+ "link": "List/ToDo",
+ "doctype": "ToDo",
+ "type": "list"
+ },
+ }
+
+
+Note: Module views are visible based on permissions.
+
+
\ No newline at end of file
diff --git a/frappe/docs/user/guides/app-development/custom-module-icon.md b/frappe/docs/user/guides/app-development/custom-module-icon.md
new file mode 100644
index 0000000000..609f7f3803
--- /dev/null
+++ b/frappe/docs/user/guides/app-development/custom-module-icon.md
@@ -0,0 +1,21 @@
+If you want to create a custom icon for your module, you will have to create an SVG file for your module and set the path to this file in the `desktop/config.py` of your app.
+
+This icon is loaded via AJAX first time, then it will be rendered.
+
+Example:
+
+ from frappe import _
+
+ def get_data():
+ return {
+ "Frappe Apps": {
+ "color": "orange",
+ "icon": "assets/frappe/images/frappe.svg",
+ "label": _("Frappe.io Portal"),
+ "type": "module"
+ }
+ }
+
+> PS: A great place to buy SVG icons for a low cost is the awesome [Noun Project](http://thenounproject.com/)
+
+
\ No newline at end of file
diff --git a/frappe/docs/user/guides/app-development/dialogs-types.md b/frappe/docs/user/guides/app-development/dialogs-types.md
new file mode 100644
index 0000000000..6b17121dd0
--- /dev/null
+++ b/frappe/docs/user/guides/app-development/dialogs-types.md
@@ -0,0 +1,118 @@
+Frappe provide a group of standard dialogs that are very usefull while coding.
+
+## Alert Dialog
+
+
+
+Is helpfull for show a non-obstrutive message.
+
+This dialog have 2 parameters `txt`that is the message and `seconds` that is the time that the message will be showed for the user, the standard is `3 seconds`.
+
+### Example
+
+ show_alert('Hi, do you have a new message', 5);
+
+---
+
+## Prompt Dialog
+
+
+
+Is helpful for ask a value for the user
+
+This dialog have 4 parameters, they are:
+
+- **fields:** a list with the fields objects
+- **callback:** the function that manage the received values
+- **title:** the title of the dialog
+- **primary_label:** the label of the primary button
+
+### Example
+
+ frappe.prompt([
+ {'fieldname': 'birth', 'fieldtype': 'Date', 'label': 'Birth Date', 'reqd': 1}
+ ],
+ function(values){
+ show_alert(values, 5);
+ },
+ 'Age verification',
+ 'Subscribe me'
+ )
+
+---
+## Confirm Dialog
+
+
+
+Usefull to get a confirmation from the user before do an action
+
+This dialog have 3 arguments, they are:
+
+- **mesage:** The message content
+- **onyes:** The callback on positive confirmation
+- **oncancel:** The callback on negative confirmation
+
+### Example
+
+ frappe.confirm(
+ 'Are you sure to leave this page?',
+ function(){
+ window.close();
+ },
+ function(){
+ show_alert('Thanks for continue here!')
+ }
+ )
+
+---
+
+## Message Print
+
+
+
+Is helpfull for show a informational dialog for the user;
+
+This dialog have 2 arguments, they are:
+
+- **message:** The message content, can be a HTML string too
+- **title:** The title of the dialog
+
+### Example
+
+ msgprint("
Server Status "
+ + "
"
+ + "
"
+ + "28% Memory "
+ + "12% Processor "
+ + "0.3% Disk "
+ " ", 'Server Info')
+
+---
+
+### Custom Dialog
+
+
+
+Frappé provide too a `Class` that you can extend and build your own custom dialogs
+
+`frappe.ui.Dialog`
+
+### Example
+
+ var d = new frappe.ui.Dialog({
+ 'fields': [
+ {'fieldname': 'ht', 'fieldtype': 'HTML'},
+ {'fieldname': 'today', 'fieldtype': 'Date', 'default': frappe.datetime.nowdate()}
+ ],
+ primary_action: function(){
+ d.hide();
+ show_alert(d.get_values());
+ }
+ });
+ d.fields_dict.ht.$wrapper.html('Hello World');
+ d.show();
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/user/guides/app-development/executing-code-on-doctype-events.md b/frappe/docs/user/guides/app-development/executing-code-on-doctype-events.md
new file mode 100644
index 0000000000..a5b57e0920
--- /dev/null
+++ b/frappe/docs/user/guides/app-development/executing-code-on-doctype-events.md
@@ -0,0 +1,29 @@
+To execute code when a DocType is inserted, validated (before saving), updated, submitted, cancelled, deleted, you must write in the DocType's controller module.
+
+#### 1. Controller Module
+
+The controller module exists in the `doctype` folder in the Module of the `DocType`. For example, the controller for **ToDo** exists in `frappe/desk/doctype/todo/todo.py` (version 5). A controller template is created when the DocType is created. which looks like
+
+ from __future__ import unicode_literals
+
+ import frappe
+ from frappe.model.document import Document
+
+ class CustomType(Document):
+ pass
+
+#### 2. Document Properties
+
+All the fields and child tables are available to the class as attributes. For example the **name** property is `self.name`
+
+#### 3. Adding Methods
+
+In this module, you can add standard methods to the class that are called when a document of that type is created. Standard Handlers are:
+
+1. `autoname`: Called while naming. You can set the `self.name` property in the method.
+1. `before_insert`: Called before a document is inserted.
+1. `validate`: Called before document is saved. You can throw an exception if you don't want the document to be saved
+1. `on_update`: Called after the document is inserted or updated in the database.
+1. `on_submit`: Called after submission.
+1. `on_cancel`: Called after cancellation.
+1. `on_trash`: Called after document is deleted.
diff --git a/frappe/docs/user/guides/app-development/fetch-custom-field-value-from-master-to-all-related-transactions.md b/frappe/docs/user/guides/app-development/fetch-custom-field-value-from-master-to-all-related-transactions.md
new file mode 100644
index 0000000000..bbf1c863c7
--- /dev/null
+++ b/frappe/docs/user/guides/app-development/fetch-custom-field-value-from-master-to-all-related-transactions.md
@@ -0,0 +1,20 @@
+Let's say, there is a custom field "VAT Number" in Supplier master, which should be fetched in Purchase Order document.
+
+
Steps:
+
1. Create a Custom Field
"VAT Number" for
Supplier document with
Field Type as
Data .
+
+
2. Create another Custom Field
"VAT Number" for Purchase Order document. But in this case, enter
Field Type as
Read Only and
Options as
supplier.vat_number .
+
3. Refresh the system using
Help -> Clear Cache .
+
4. Now on selection of Supplier in new Purchase Order form, "VAT Number" will be fetched automatically from Supplier master.
+
5. The above procedure should be replicated, for all other supplier related transactions.
+
+
Note:
+
+
If field type of "VAT Number" in Purchase Order is other than `Read Only`, then to fetch the value, a small piece of Custom Script need to be written.
+ i. Go to Setup -> Customize -> Custom Script.
+ ii. Select DocType as `Purchase Order`.
+ iii. Add Script `cur_frm.add_fetch('supplier', 'vat_number', 'vat_number')`
+ iv. Save the Custom Script.
+ v. Clear cache before testing.
+
+
\ No newline at end of file
diff --git a/frappe/docs/user/guides/app-development/generating-docs.md b/frappe/docs/user/guides/app-development/generating-docs.md
new file mode 100644
index 0000000000..ca3d92a61d
--- /dev/null
+++ b/frappe/docs/user/guides/app-development/generating-docs.md
@@ -0,0 +1,110 @@
+# Generating Documentation Website for your App
+
+Frappe version 6.7 onwards includes a full-blown documentation generator so that you can easily create a website for your app that has both user docs and developers docs (auto-generated). These pages are generated as static HTML pages so that you can add them as GitHub pages.
+
+## Writing Docs
+
+### 1. Setting up docs
+
+#### 1.1. Setup `docs.py`
+
+The first step is to setup the docs folder. For that you must create a new file in your app `config/docs.py` if it is not auto-generated. In your `docs.py` file, add the following module properties.
+
+
+ source_link = "https://github.com/[orgname]/[reponame]"
+ docs_base_url = "https://[orgname].github.io/[reponame]"
+ headline = "This is what my app does"
+ sub_heading = "Slightly more details with key features"
+ long_description = """(long description in markdown)"""
+
+ def get_context(context):
+ # optional settings
+
+ # context.brand_html = 'Brand info on the top left'
+ # context.favicon = 'path to favicon'
+ #
+ # context.top_bar_items = [
+ # {"label": "About", "url": context.docs_base_url + "/about"},
+ # ]
+
+ pass
+
+#### 1.2. Generate `/docs`
+
+To generate the docs for the `current` version, go to the command line and write
+
+ bench --site sitename make-docs app_name current
+
+If you want to maintain versions of your docs, then you can add a version number instead of `current`
+
+This will create a `/docs` folder in your app.
+
+### 2. Add User Documentation
+
+To add user documentation, add folders and pages in your `/docs/user` folder in the same way you would build a website pages in the `www` folder.
+
+Some quick tips:
+
+1. Add your pages as `.md` or `.html` pages
+2. Optionally add `.css` files with the same name that will be automatically served
+3. Add index by adding `{index}`
+
+### 3. Linking
+
+While linking make sure you add `{{ docs_base_url }}` to all your links.
+
+
+ {% raw %}
Link Description {% endraw %}
+
+
+### 4. Adding Images
+
+You can add images in the `/docs/assets` folder. You can add links to the images as follows:
+
+ {% raw %}
{% endraw %}
+
+---
+
+## Setting up output docs
+
+1. Create a `/docs` folder in your bench, parallel to your `/sites` folder. e.g. `/frappe-bench/docs`
+2. Copy the repo of your app to the docs folder. e.g. `cp -R apps/myapp docs/myapp` (you can also clone it here using `git clone`).
+3. Go to your docs folder `cd docs/myapp`
+4. Checkout the gh-pages branch `git checkout --orphan gh-pages`
+5. Clean everything `git rm -rf .`
+
+Note > The branch name `gh-pages` is only if you are using GitHub. If you are hosting this on any other static file server, can just skip this and just create your docs folder for your app like `docs/myapp`
+
+Putting it all together:
+
+ mkdir docs
+ cp -R apps/myapp docs/myapp
+ cd docs/myapp
+ git checkout --orphan gh-pages
+ git rm -rf .
+
+---
+
+## Viewing Locally
+
+To test your docs locally, add a `--local` option to the `build-docs` command.
+
+ bench --site [site] build-docs [appname] --local
+
+Then it will build urls so that you can view these files locally. To view them locally in your browser, you can use the Python SimpleHTTPServer
+
+Run this from your `docs/myapp` folder:
+
+ python -m SimpleHTTPServer 8080
+
+---
+
+## Publishing to GitHub Pages
+
+To publish your docs on GitHub pages, you will have to create an empty and orphan branch in your repository called `gh-pages` and write yours there
+
+Now go back to your bench folder and write these docs to this branch. For example if your path to the `gh-pages` repo is `docs/reponame`
+
+ bench --site [site] build-docs [appname]
+
+To check your documentation online go to: https://[orgname].github.io/[reponame]
diff --git a/frappe/docs/user/guides/app-development/how-enable-developer-mode-in-frappe.md b/frappe/docs/user/guides/app-development/how-enable-developer-mode-in-frappe.md
new file mode 100644
index 0000000000..5c47385fbd
--- /dev/null
+++ b/frappe/docs/user/guides/app-development/how-enable-developer-mode-in-frappe.md
@@ -0,0 +1,15 @@
+When you are in application design mode and you want the changes in your DocTypes, Reports etc to affect the app repository, you must be in **Developer Mode**.
+
+To enable developer mode, update the `site_config.json` file of your site in the sites folder for example:
+
+ frappe-bench/sites/site1/site_config.json
+
+Add this to the JSON object
+
+ "developer_mode": 1
+
+After setting developer mode, clear the cache:
+
+ $ bench clear-cache
+
+
diff --git a/frappe/docs/user/guides/app-development/how-to-create-custom-fields-during-app-installation.md b/frappe/docs/user/guides/app-development/how-to-create-custom-fields-during-app-installation.md
new file mode 100644
index 0000000000..20b7fdce30
--- /dev/null
+++ b/frappe/docs/user/guides/app-development/how-to-create-custom-fields-during-app-installation.md
@@ -0,0 +1,20 @@
+Your custom app can automatically add **Custom Fields** to DocTypes outside of your app when it is installed to a new site.
+
+To do this, add the new custom fields that your app requires, using the Frappe web application.
+
+In your `hooks.py` file, add `"Custom Fields"`
+
+ fixtures = ["Custom Field"]
+
+Export fixtures before you commit your app with:
+
+ $ bench --site mysite export-fixtures
+
+This will create a new folder called `fixtures` in your app folder and a `.csv` or `.json` file will be created with the definition of the custom fields you added.
+
+This file will be automatically imported when the app is installed in a new site or updated via `bench update`.
+
+Note: You can also add single DocTypes like "Website Settings" as fixtures
+
+
+
diff --git a/frappe/docs/user/guides/app-development/how-to-improve-a-standard-control.md b/frappe/docs/user/guides/app-development/how-to-improve-a-standard-control.md
new file mode 100644
index 0000000000..bfbf320612
--- /dev/null
+++ b/frappe/docs/user/guides/app-development/how-to-improve-a-standard-control.md
@@ -0,0 +1,102 @@
+Frappé has a couple of elegant and useful widgets, but some times we need to edit them to add small improvements. This small article will describe how to add new resources to the standard widgets.
+
+Let me explain first our goal:
+
+> Add `many` alternative translations in `numerous records` and in a `lot of doctypes`
+
+Look the highlighted sections in the __goal__, we have _many translations_ to add in _many records_ and in _many doctypes_, so, we heave a **many of work**, so we have a lot to do right?
+
+The answer for this question is: _-Of course not! Because we know that if one element exists in many records and in many doctypes, this element is the `Control` or `Widget`_
+
+So, what we need do, is improve your goal based on the `Control`, to reduce our quantity of work.
+
+But, where will we find this magic element, the control? _-For now, we can look it in the JavaScript sources - let's look now at [Github](https://github.com/frappe/frappe/blob/develop/frappe/public/js/frappe/form/control.js#L13)_
+
+> Don't worry if you don't understand the code for now, our goal there is simplify our work.
+
+Let's go ahead with the thought!
+
+We know where we need to make the changes, but how will we dismember which are the controls that are affected by our feature and which aren't ?
+
+We need to keep in mind, that `Control` are instance of `DocFields` and the `DocFields` have a field that is very important for us in this case, the field that will help us to dismember which are affected by our feature and which aren't is the field `options` in the `DocField`.
+
+_-Wait!, we understood that the field `options` can help us, but, how will it help us?_
+
+Good question, we will define a word to put in the `options` of the `DocFields` that we need to include the feature, this world will be **`Translatable`.**
+
+> If you forget how to customize the options of a field look [this article](https://kb.erpnext.com/kb/customize/creating-custom-link-field), it can refresh your knowledge.
+
+Well, with the defined word in `options` of our selected `DocFields`, now is time to code:
+
+_-At last, we think we would never stop talking!_
+
+ frappe.ui.form.ControlData = frappe.ui.form.ControlData.$extend({
+ make_input: function(){
+ var options = this.df.options;
+ if (!options || options!=="Translatable"){
+ this._super();
+ return;
+ }
+ var me = this;
+ $('
').prependTo(this.input_area);
+ this.$input_area = $(this.input_area);
+ this.$input = this.$input_area.find('input');
+ this.$btn = this.$input_area.find('.dialog-btn');
+ this.set_input_attributes();
+ this.$input.on("focus", function(){
+ me.$btn.toggle(true);
+ });
+ this.$input.on("blur", function(){
+ setTimeout(function(){ me.$btn.toggle(false) }, 500);
+ });
+ this.input = $this.input.get(0);
+ this.has_input = true;
+ var me = this;
+ this.setup_button();
+ },
+ setup_button: function(){
+ var me = this;
+ if (this.only_input){
+ this.$btn.remove();
+ return;
+ }
+ this.$btn.on("click", function(){
+ var value = me.get_value();
+ var options = me.df.options;
+ if (value && options && options==="Translatable"){
+ this.open_dialog();
+ }
+ });
+ },
+ open_dialog: function(){
+ var doc = this.doc;
+ if (!doc.__unsaved){
+ new frappe.ui.form.TranslationSelector({
+ doc: doc,
+ df: this.doc,
+ text: this.value
+ });
+ }
+ }
+ });
+
+_-Other letter soup, for my gosh!_
+
+In fact, it IS a soup of letters, for a newbie, but we are not a beginner.
+
+Let me explain what this code does;
+
+ - At line 1 the code overrides the `ControlData` by one extended `Class` of itself.
+ - The method `make_input` checks if the docfield is **`Translatable`** to make the new `Control` if not, it calls the *original* `make_input` using `_super()`
+ - The method `setup_button` checks if the docfield is **`Translatable`** to enable it show a `dialog`
+ - The method `open_dialog` invokes a new instance of the `TranslationSelector` that we will create in the code below.
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/user/guides/app-development/index.md b/frappe/docs/user/guides/app-development/index.md
new file mode 100644
index 0000000000..b04ae83043
--- /dev/null
+++ b/frappe/docs/user/guides/app-development/index.md
@@ -0,0 +1,3 @@
+# App Development
+
+{index}
diff --git a/frappe/docs/user/guides/app-development/index.txt b/frappe/docs/user/guides/app-development/index.txt
new file mode 100644
index 0000000000..32b9c08c0d
--- /dev/null
+++ b/frappe/docs/user/guides/app-development/index.txt
@@ -0,0 +1,14 @@
+adding-module-icons-on-desktop
+custom-module-icon
+generating-docs
+how-enable-developer-mode-in-frappe
+fetch-custom-field-value-from-master-to-all-related-transactions
+executing-code-on-doctype-events
+how-to-add-customizations-to-app
+insert-a-document-via-api
+how-to-improve-a-standard-control
+overriding-link-query-by-custom-script
+single-type-doctype
+trigger-event-on-deletion-of-grid-row
+dialogs-types
+using-html-templates-in-javascript
diff --git a/frappe/docs/user/guides/app-development/insert-a-document-via-api.md b/frappe/docs/user/guides/app-development/insert-a-document-via-api.md
new file mode 100644
index 0000000000..aab15b4ac9
--- /dev/null
+++ b/frappe/docs/user/guides/app-development/insert-a-document-via-api.md
@@ -0,0 +1,53 @@
+You can insert documents via a script using the `frappe.get_doc` method
+
+### Examples:
+
+#### 1. Insert a ToDo
+
+ todo = frappe.get_doc({"doctype":"ToDo", "description": "test"})
+ todo.insert()
+
+---
+
+#### 2. Insert without the user's permissions being checked:
+
+ todo = frappe.get_doc({"doctype":"ToDo", "description": "test"})
+ todo.insert(ignore_permissions = True)
+
+
+---
+
+#### 3. Submit after inserting
+
+ todo = frappe.get_doc({"doctype":"ToDo", "description": "test"})
+ todo.insert(ignore_permissions=True)
+ todo.submit()
+
+---
+
+#### 4. Insert a document on saving of another document
+
+ class MyType(Document):
+ def on_update(self):
+ todo = frappe.get_doc({"doctype":"ToDo", "description": "test"})
+ todo.insert()
+
+----
+
+#### 5. Insert a document with child tables:
+
+ sales_order = frappe.get_doc({
+ "doctype": "Sales Order",
+ "company": "_Test Company",
+ "customer": "_Test Customer",
+ "delivery_date": "2013-02-23",
+ "sales_order_details": [
+ {
+ "item_code": "_Test Item Home Desktop 100",
+ "qty": 10.0,
+ "rate": 100.0,
+ "warehouse": "_Test Warehouse - _TC"
+ }
+ ]
+ })
+ sales_order.insert()
diff --git a/frappe/docs/user/guides/app-development/overriding-link-query-by-custom-script.md b/frappe/docs/user/guides/app-development/overriding-link-query-by-custom-script.md
new file mode 100644
index 0000000000..cc8c8058fd
--- /dev/null
+++ b/frappe/docs/user/guides/app-development/overriding-link-query-by-custom-script.md
@@ -0,0 +1,87 @@
+You can override the standard link query by using `set_query`
+
+### 1. Adding Fitlers
+
+You can add filters to the query:
+
+ frappe.ui.form.on("Bank Reconciliation", "onload", function(frm) {
+ cur_frm.set_query("bank_account", function() {
+ return {
+ "filters": {
+ "account_type": "Bank",
+ "group_or_ledger": "Ledger"
+ }
+ };
+ });
+ });
+
+A more complex query:
+
+ frappe.ui.form.on("Bank Reconciliation", "onload", function(frm){
+ cur_frm.set_query("bank_account", function(){
+ return {
+ "filters": [
+ ["Bank Account": "account_type", "=", "Bank"],
+ ["Bank Account": "group_or_ledger", "!=", "Group"]
+ ]
+ }
+ });
+ });
+
+---
+
+### 2. Calling a Different Method to Generate Results
+
+You can also set a server side method to be called on the query:
+
+ frm.set_query("item_code", "items", function() {
+ return {
+ query: "erpnext.controllers.queries.item_query",
+ filters: frm.doc.enquiry_type === "Maintenance" ?
+ {"is_service_item": "Yes"} : {"is_sales_item": "Yes"}
+ };
+ });
+
+
+
+#### Custom Method
+
+The custom method should return a list of items for auto select. If you want to send additional data, you can send multiple columns in the list.
+
+Parameters to the custom method are:
+
+`def custom_query(doctype, txt, searchfield, start, page_len, filters)`
+
+**Example:**
+
+ # searches for leads which are not converted
+ def lead_query(doctype, txt, searchfield, start, page_len, filters):
+ return frappe.db.sql("""select name, lead_name, company_name from `tabLead`
+ where docstatus < 2
+ and ifnull(status, '') != 'Converted'
+ and ({key} like %(txt)s
+ or lead_name like %(txt)s
+ or company_name like %(txt)s)
+ {mcond}
+ order by
+ if(locate(%(_txt)s, name), locate(%(_txt)s, name), 99999),
+ if(locate(%(_txt)s, lead_name), locate(%(_txt)s, lead_name), 99999),
+ if(locate(%(_txt)s, company_name), locate(%(_txt)s, company_name), 99999),
+ name, lead_name
+ limit %(start)s, %(page_len)s""".format(**{
+ 'key': searchfield,
+ 'mcond':get_match_cond(doctype)
+ }), {
+ 'txt': "%%%s%%" % txt,
+ '_txt': txt.replace("%", ""),
+ 'start': start,
+ 'page_len': page_len
+ })
+
+
+
+For more examples see:
+
+[https://github.com/frappe/erpnext/blob/develop/erpnext/controllers/queries.py](https://github.com/frappe/erpnext/blob/develop/erpnext/controllers/queries.py)
+
+
\ No newline at end of file
diff --git a/frappe/docs/user/guides/app-development/single-type-doctype.md b/frappe/docs/user/guides/app-development/single-type-doctype.md
new file mode 100644
index 0000000000..ee5c24b492
--- /dev/null
+++ b/frappe/docs/user/guides/app-development/single-type-doctype.md
@@ -0,0 +1,9 @@
+DocTypes have a table associated with them. For example DocType **Customer** will have a table `tabCustomer` associated with it.
+
+**Single** type DocTypes have no table associated and there is only one Document for it. This is similar to the Singleton pattern in Java. Single DocTypes are ideal for saving Settings (that are globally applicable) and for wizard / helper type forms that have no documents, but when the DocType is used for the Form UI.
+
+The data in Single DocType is stored in `tabSingles` (`doctype`, `field`, `value`)
+
+#### Examples
+
+In Frappe, Single types are **System Settings** and **Customize Form**
\ No newline at end of file
diff --git a/frappe/docs/user/guides/app-development/trigger-event-on-deletion-of-grid-row.md b/frappe/docs/user/guides/app-development/trigger-event-on-deletion-of-grid-row.md
new file mode 100644
index 0000000000..68f1b77129
--- /dev/null
+++ b/frappe/docs/user/guides/app-development/trigger-event-on-deletion-of-grid-row.md
@@ -0,0 +1,22 @@
+
+To trigger an event when a row from a grid has been deleted, you need to add a handler the `fieldname_remove` event, where fieldname is the fieldname of the grid (Table)
+
+
Example for add
+
+
Recalculate totals when a Journal Entry row has been added
+
+ frappe.ui.form.on("Journal Entry Account", "accounts_add", function(frm){
+ cur_frm.cscript.update_totals(frm.doc);
+ });
+
+
+
+
Example for delete
+
+
Recalculate totals when a Journal Entry row has been deleted
+
+ frappe.ui.form.on("Journal Entry Account", "accounts_remove", function(frm){
+ cur_frm.cscript.update_totals(frm.doc);
+ });
+
+
\ No newline at end of file
diff --git a/frappe/docs/user/guides/app-development/using-html-templates-in-javascript.md b/frappe/docs/user/guides/app-development/using-html-templates-in-javascript.md
new file mode 100644
index 0000000000..db0cd90b4c
--- /dev/null
+++ b/frappe/docs/user/guides/app-development/using-html-templates-in-javascript.md
@@ -0,0 +1,42 @@
+Often while building javascript interfaces, there is a need to render DOM as an HTML template. Frappe Framework uses John Resig's Microtemplate script to render HTML templates in the Desk application.
+
+> Note 1: In Frappe we use the Jinja-like `{%` tags to embed code rather than the standard `<%`
+
+> Note 2: Never use single quotes `'` inside the HTML template.
+
+To render a template,
+
+1. Create a template `html` file in your app. e.g. `address_list.html`
+1. Add it to `build.json` for your app (you can include it in `frappe.min.js` or your own javascript file).
+1. To render it in your app, use `frappe.render(frappe.templates.address_list, {[context]})`
+
+#### Example Template:
+
+From `erpnext/public/js/templates/address_list.js`
+
+
+
+ New Address
+ {% for(var i=0, l=addr_list.length; i
+
+ {%= __("Edit") %}
+ {%= addr_list[i].address_type %}
+
+
+ {% if(addr_list[i].is_primary_address) { %}
+ {%= __("Primary") %} {% } %}
+ {% if(addr_list[i].is_shipping_address) { %}
+ {%= __("Shipping") %} {% } %}
+
+
{%= addr_list[i].display %}
+
+ {% } %}
+ {% if(!addr_list.length) { %}
+ {%= __("No address added yet.") %}
+ {% } %}
+
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/user/guides/basics/apps.md b/frappe/docs/user/guides/basics/apps.md
new file mode 100644
index 0000000000..f79a9f4642
--- /dev/null
+++ b/frappe/docs/user/guides/basics/apps.md
@@ -0,0 +1,109 @@
+# Frappe Apps
+
+Frappe Apps are Python packages which use the Frappe platform. They can live
+anywhere on the [Python
+path](https://docs.python.org/2/tutorial/modules.html#the-module-search-path)
+and must have an entry in the `apps.txt` file.
+
+
+### Creating an app
+
+Frappe ships with a boiler plate for a new app. The command `bench make-app
+app-name` helps you start a new app by starting an interactive shell.
+
+
+ % bench make-app sample_app
+ App Name: sample_app
+ App Title: Sample App
+ App Description: This is a sample app.
+ App Publisher: Acme Inc.
+ App Icon: icon-linux
+ App Color: #6DAFC9
+ App Email: info@example.com
+ App URL: http://example.com
+ App License: MIT
+
+The above command would create an app with the following directory structure.
+
+ sample_app
+ ├── license.txt
+ ├── MANIFEST.in
+ ├── README.md
+ ├── sample_app
+ │ ├── __init__.py
+ │ ├── sample_app
+ │ │ └── __init__.py
+ │ ├── config
+ │ │ ├── desktop.py
+ │ │ └── __init__.py
+ │ ├── hooks.py
+ │ ├── modules.txt
+ │ ├── patches.txt
+ │ └── templates
+ │ ├── generators
+ │ │ └── __init__.py
+ │ ├── __init__.py
+ │ ├── pages
+ │ │ └── __init__.py
+ │ └── statics
+ └── setup.py
+
+Here, "App Icon" is a font awesome class that you can select from
+[http://fortawesome.github.io/Font-Awesome/icons/](http://fortawesome.github.io/Font-Awesome/icons/).
+
+The boiler plate contains just enough files to show your app icon on the [Desk].
+
+### Files in the app
+
+#### `hooks.py`
+
+The `hooks.py` file defines the metadata of your app and integration points
+with other parts of Frappe or Frappe apps. Examples of such parts include task
+scheduling or listening to updates to different documents in the system. For
+now, it just contains the details you entered during app creation.
+
+
+ app_name = "sample-app"
+ app_title = "Sample App"
+ app_publisher = "Acme Inc."
+ app_description = "This is a sample app."
+ app_icon = "fa-linux"
+ app_color = "black"
+ app_email = "info@example.com"
+ app_url = "http://example.com"
+ app_version = 0.0.1
+
+#### `modules.txt`
+
+Modules in Frappe help you organize Documents in Frappe and they are defined in
+the `modules.txt` file in your app. It is necessary for every [DocType] to be
+attached to a module. By default a module by the name of your app is added.
+Also, each module gets an icon on the [Desk]. For example, the [ERPNext] app is
+organized in the following modules.
+
+ accounts
+ buying
+ home
+ hr
+ manufacturing
+ projects
+ selling
+ setup
+ stock
+ support
+ utilities
+ contacts
+
+### Adding app to a site
+
+Once you have an app, whether it's the one you just created or any other you
+downloaded, you are required to do the following things.
+
+Download the app via git
+
+ bench get-app https://github.com/org/app_name
+
+Install the app to your site
+
+ bench --site app_name install-app app_name
+
diff --git a/frappe/docs/user/guides/basics/hooks.md b/frappe/docs/user/guides/basics/hooks.md
new file mode 100644
index 0000000000..9bfaaeee3c
--- /dev/null
+++ b/frappe/docs/user/guides/basics/hooks.md
@@ -0,0 +1,273 @@
+# Hooks
+
+
+Hooks are the duct tape of the Frappe system. Hooks allow you to "hook" in to
+functionality and events of other parts of the Frappe system. Following are the
+official hooks from Frappe.
+
+### Application Name and Details
+
+1. `app_name` - slugified name with underscores e.g. "shopping\_cart"
+2. `app_title` - full title name e.g. "Frappe"
+3. `app_publisher`
+4. `app_description`
+5. `app_version`
+6. `app_icon` - font-awesome icon or image url
+7. `app_color` - hex colour background of the app icon
+
+### Install Events
+
+1. `before_install`
+2. `after_install`
+
+The above hooks are called before and after installation of the app they are in.
+For example, [ERPNext](/apps/erpnext)'s hooks contains a line,
+
+ after_install = "erpnext.setup.install.after_install"
+
+So, the function after\_install is imported and called after ERPNext is installed.
+
+Note, the `before_install` and `after_install` hooks are called with no arguments.
+
+### Boot Session
+
+After a successful login, the Frappe JS Client requests for a resource called
+`bootinfo`. The `bootinfo` is available as a global in Javascript via
+`frappe.boot`. By default, the `bootinfo` contains
+
+* System defaults
+* Notification status
+* Permissions
+* List of icons on desktop
+* User settings
+* Language and timezone info
+
+If your app wants to modify bootinfo, it can declare a hook `boot_session`. The
+value is assumed to be a dotted path to a function and is called with one
+argument, bootinfo which it can modify and return.
+
+Eg,
+
+ boot_session = "erpnext.startup.boot.boot_session"
+
+### Notification configurations
+
+The notification configuration hook is expected to return a Python dictionary.
+
+ {
+ "for_doctype": {
+ "Issue": {"status":"Open"},
+ "Customer Issue": {"status":"Open"},
+ },
+ "for_module_doctypes": {
+ "ToDo": "To Do",
+ "Event": "Calendar",
+ "Comment": "Messages"
+ },
+ "for_module": {
+ "To Do": "frappe.core.notifications.get_things_todo",
+ "Calendar": "frappe.core.notifications.get_todays_events",
+ "Messages": "frappe.core.notifications.get_unread_messages"
+ }
+ }
+
+
+The above configuration has three parts,
+
+1. `for_doctype` part of the above configuration marks any "Issue"
+ or "Customer Issue" as unread if its status is Open
+2. `for_module_doctypes` maps doctypes to module's unread count.
+3. `for_module` maps modules to functions to obtain its unread count. The
+ functions are called without any argument.
+
+### Javascript / CSS Assets
+
+The following hooks allow you to bundle built assets to your app for serving.
+There are two types of assets, app and web. The app assets are loaded in the
+Desk and web assets are loaded in the website.
+
+1. `app_include_js`
+2. `app_include_css`
+3. `web_include_js`
+4. `web_include_css`
+
+Eg,
+
+ app_include_js = "assets/js/erpnext.min.js"
+ web_include_js = "assets/js/erpnext-web.min.js"
+
+Note: to create an asset bundle (eg, assets/js/erpnext.min.js) the target file
+should be in build.json of your app.
+
+### Configuring Reports
+
+In the report view, you can force filters as per doctype using `dump_report_map`
+hook. The hook should be a dotted path to a Python function which will be called
+without any arguments. Example of output of this function is below.
+
+
+ "Warehouse": {
+ "columns": ["name"],
+ "conditions": ["docstatus < 2"],
+ "order_by": "name"
+ }
+
+Here, for a report with Warehouse doctype, would include only those records that
+are not cancelled (docstatus < 2) and will be ordered by name.
+
+### Modifying Website Context
+
+Context used in website pages can be modified by adding
+a `update_website_context` hook. This hook should be a dotted path to a function
+which will be called with a context (dictionary) argument.
+
+### Customizing Email footer
+
+By default, for every email, a footer with content, "Sent via Frappe" is sent.
+You can customize this globally by adding a `mail_footer` hook. The hook should
+be a dotted path to a variable.
+
+### Session Creation Hook
+
+You can attach custom logic to the event of a successful login using
+`on_session_creation` hook. The hook should be a dotted path to a Python
+function that takes login\_manager as an argument.
+
+Eg,
+
+ def on_session_creation(login_manager):
+ """make feed"""
+ if frappe.session['user'] != 'Guest':
+ # log to timesheet
+ pass
+
+### Website Clear Cache
+
+If you cache values in your views, the `website_clear_cache` allows you to hook
+methods that invalidate your caches when Frappe tries to clear cache for all
+website related pages.
+
+### Document hooks
+
+#### Permissions
+
+#### Query Permissions
+You can customize how permissions are resolved for a DocType by hooking custom
+permission match conditions using the `permission_query_conditions` hook. This
+match condition is expected to be fragment for a where clause in an sql query.
+Structure for this hook is as follows.
+
+
+ permission_query_conditions = {
+ "{doctype}": "{dotted.path.to.function}",
+ }
+
+The output of the function should be a string with a match condition.
+Example of such a function,
+
+
+ def get_permission_query_conditions():
+ return "(tabevent.event_type='public' or tabevent.owner='{user}'".format(user=frappe.session.user)
+
+The above function returns a fragment that permits an event to listed if it's
+public or owned by the current user.
+
+#### Document permissions
+You can hook to `doc.has_permission` for any DocType and add special permission
+checking logic using the `has_permission` hook. Structure for this hook is,
+
+ has_permission = {
+ "{doctype}": "{dotted.path.to.function}",
+ }
+
+The function will be passed the concerned document as an argument. It should
+True or a falsy value after running the required logic.
+
+For Example,
+
+ def has_permission(doc):
+ if doc.event_type=="Public" or doc.owner==frappe.session.user:
+ return True
+
+The above function permits an event if it's public or owned by the current user.
+
+#### CRUD Events
+
+You can hook to various CRUD events of any doctype, the syntax for such a hook
+is as follows,
+
+ doc_events = {
+ "{doctype}": {
+ "{event}": "{dotted.path.to.function}",
+ }
+ }
+
+To hook to events of all doctypes, you can use the follwing syntax also,
+
+ doc_events = {
+ "*": {
+ "on_update": "{dotted.path.to.function}",
+ }
+ }
+
+The hook function will be passed the doc in concern as the only argument.
+
+##### List of events
+
+* `validate`
+* `before_save`
+* `after_save`
+* `before_insert`
+* `after_insert`
+* `before_submit`
+* `before_cancel`
+* `before_update_after_submit`
+* `on_update`
+* `on_submit`
+* `on_cancel`
+* `on_update_after_submit`
+
+
+Eg,
+
+ doc_events = {
+ "Cab Request": {
+ "after_insert": topcab.schedule_cab",
+ }
+ }
+
+### Scheduler Hooks
+
+Scheduler hooks are methods that are run periodically in background. Structure for such a hook is,
+
+ scheduler_events = {
+ "{event_name}": [
+ "{dotted.path.to.function}"
+ ],
+ }
+
+#### Events
+
+* `daily`
+* `daily_long`
+* `weekly`
+* `weekly_long`
+* `monthly`
+* `monthly_long`
+* `hourly`
+* `all`
+
+The scheduler events require celery, celerybeat and redis (or a supported and
+configured broker) to be running. The events with suffix '\_long' are for long
+jobs. The `all` event is triggered everytime (as per the celerybeat interval).
+
+Example,
+
+ scheduler_events = {
+ "{daily}": [
+ "erpnext.accounts.doctype.sales_invoice.sales_invoice.manage_recurring_invoices"
+ ],
+ "{daily_long}": [
+ "erpnext.setup.doctype.backup_manager.backup_manager.take_backups_daily"
+ ],
+ }
diff --git a/frappe/docs/user/guides/basics/index.md b/frappe/docs/user/guides/basics/index.md
new file mode 100644
index 0000000000..645bed29a7
--- /dev/null
+++ b/frappe/docs/user/guides/basics/index.md
@@ -0,0 +1,3 @@
+# Basics
+
+{index}
diff --git a/frappe/docs/user/guides/basics/index.txt b/frappe/docs/user/guides/basics/index.txt
new file mode 100644
index 0000000000..910ba191d4
--- /dev/null
+++ b/frappe/docs/user/guides/basics/index.txt
@@ -0,0 +1,7 @@
+install
+apps
+sites
+site_config
+hooks
+translations
+writing-tests
diff --git a/frappe/docs/user/guides/basics/install.md b/frappe/docs/user/guides/basics/install.md
new file mode 100644
index 0000000000..3afa43a37c
--- /dev/null
+++ b/frappe/docs/user/guides/basics/install.md
@@ -0,0 +1,10 @@
+# Installing Frappe
+
+## Frappe bench
+
+The following steps help you setup an isolated environment (bench) to run and
+develop Frappe apps. A virtualenv is installed in the env directory. You can
+activate it by running `source ./env/bin/activate` or use execute using
+absolute/relative path (eg, `./env/bin/frappe`).
+
+For more info, see [Frappe Bench](https://github.com/frappe/bench/)
diff --git a/frappe/docs/user/guides/basics/site_config.md b/frappe/docs/user/guides/basics/site_config.md
new file mode 100644
index 0000000000..322cc1937c
--- /dev/null
+++ b/frappe/docs/user/guides/basics/site_config.md
@@ -0,0 +1,40 @@
+# Site Config
+
+Settings for `sites/[site]/site_config.json`
+
+`site_config.json` stores global settings for a particular site and is present in the site directory. Here is a list of properties you can set in `site_config.json`.
+
+Example:
+
+ {
+ "db_name": "test_frappe",
+ "db_password": "test_frappe",
+ "admin_password": "admin",
+ }
+
+### Mandatory Settings
+
+- `db_name`: Database Name.
+- `db_password`: Database password.
+
+### Optional Settings
+
+- `db_host`: Database host if not `localhost`.
+- `admin_password`: Default Password for "Administrator".
+- `mute_emails`: Stops email sending if true.
+- `deny_multiple_logins`: Stop users from having more than one active session.
+- `root_password`: MariaDB root password.
+
+### Defaut Outgoing Email Settings
+
+- `mail_server`: SMTP server hostname.
+- `mail_port`: STMP port.
+- `use_ssl`: Connect via SSL / TLS.
+- `mail_login`: Login id for SMTP server.
+- `mail_password`: Password for SMTP server.
+
+### Developer Settings
+
+- `developer_mode`: If developer mode is set, DocType changes are automatically updated in files.
+- `disable_website_cache`: Don't cache website pages.
+- `logging`: writes logs if **1**, writes queries also if set to **2**.
diff --git a/frappe/docs/user/guides/basics/sites.md b/frappe/docs/user/guides/basics/sites.md
new file mode 100644
index 0000000000..81f51aa599
--- /dev/null
+++ b/frappe/docs/user/guides/basics/sites.md
@@ -0,0 +1,82 @@
+# Sites
+
+## Sites Directory
+
+Frappe is a multitenant platform and each tenant is called a site. Sites exist
+in a directory called `sites_dir`, assumed as the current working directory when
+running a frappe command or other services like Celery worker or a WSGI server.
+
+You can set `sites_dir` with an environment variable `SITES_DIR` or pass
+`--sites_dir` option to the frappe command.
+
+Apart from the sites, the `sites_dir` should contain the following.
+
+#### apps.txt
+
+`apps.txt` contain a list of Python packages to treat as Frappe apps. Every
+frappe app that you intend to use in you site should have an entry in this file.
+Also, they should be in the `PYTHONPATH`. For more information, refer
+[Frappe Apps](/help/apps).
+
+#### common\_site\_config.json
+
+`common_site_config.json` is an optional file. Configuration common to all sites
+can be put in this file.
+
+#### assets
+
+Assets contain files that are required to be served for the browser client.
+These generally include *.js, *.css, *.png files. This directory is auto
+generated using the `bench build` command.
+
+#### languages.txt
+
+`languages.txt` is an autogenerated file which maps every language to it's code.
+
+## Site
+
+A site is a directory in `sites_dir` which represents a tenant in Frappe Platform.
+
+
+### Directory Structure
+
+ site
+ ├── locks
+ ├── private
+ │ └── backups
+ ├── public
+ │ └── files
+ │ └── testfile.txt
+ └── site_config.json
+
+* `locks` directory is used by the scheduler to synchronize various jobs using
+the [file locking concept](http://en.wikipedia.org/wiki/File_locking).
+
+* `private` directory contains files that require authentication to access.
+Presently, it is limited only to backups.
+
+* `public` directory contains files that can directly served. In the above
+ example, `testfile.txt` can be accessed by the URL,
+ http://site/files/testfile.txt
+
+* `site_config.json` contains site specific configuration
+
+### Site Config
+
+[See configuration options for `site_config.json`](/docs/user-guide/site_config.md)
+
+### Site Resolution
+
+While responding to an HTTP request, a site is automatically selected based on,
+
+* `Host` header in the HTTP request matches a site
+* `X-Frappe-Site-Name` header in the HTTP request matches a site
+
+It is also possible to force the development server to serve a specific site by
+starting it with the following command.
+ `bench --site SITENAME serve`
+
+
+### Adding a new site
+
+`frappe new-site SITENAME`
diff --git a/frappe/docs/user/guides/basics/translations.md b/frappe/docs/user/guides/basics/translations.md
new file mode 100644
index 0000000000..e5ff22e9f2
--- /dev/null
+++ b/frappe/docs/user/guides/basics/translations.md
@@ -0,0 +1,86 @@
+
+
+
+This document shows how to translations are managed in ERPNext and how to add
+a new language or update translations of an existing language.
+
+### 1. Source
+
+Translatable text exists in 3 main sources:
+
+ 1. Javascript Code Files (both framework and application)
+ 2. Python Code Files
+ 3. DocTypes (names, labels and select options)
+
+#### Strings in Code Files
+
+Strings in code files are annotated using the `_` (underscore) method
+
+ 1. In Python it is the `frappe._` method. Example:
+
+`frappe._("String {0} must be translated".format(txt))`
+
+ 2. In Javascript it is the `__` method. Example:
+
+`__("String {0} must be translated", [txt])`
+
+**Note:** If you find translatable strings are not properly annotated using the `_`
+method, you can add them in the code and rebuild the translations.
+
+### 2. How Translations Are Picked up During Execution
+
+Whenever a translation is called via the _ method, the entire translation
+dictionaries from all apps are built and stored in memcache.
+
+Based on the user preferences or request preferences, the appropriate
+translations are loaded at the time of request on the server side. Or if
+metadata (DocType) is queried, then the appropriate translations are appended
+when the DocType data is requested.
+
+The underscore `_` method will replace the strings based on the available
+translations loaded at the time.
+
+### 3. Adding New Translations
+
+1. To find untranslated strings, run `bench get-untranslated [lang] [path]`
+1. Add the translated strings in another file in the same order
+1. run `bench update-translations [lang] [path of untranslated strings] [path of translated strings]`
+
+### 4. Improving Translations:
+
+For updating translations, please go to the to [the translation portal](https://frappe.io/translator).
+
+If you want to do it directly via code:
+
+To improve an existing translation, just edit the master translation files in
+the `translations` of each app
+
+> Please contribute your translations back to ERPNext by sending us a Pull
+Request.
+
+### 5. Bootstrapping a New Language
+
+If you want to add a new language it is similar to adding new translations. You need to first export all the translations strings in one file, get them translated via Google Translate Tool or Bing Translate Tool and then import the translations into individual apps.
+
+**Step 1: Export to a file**
+
+ $ bench get-untranslated [lang] [path]
+
+**Step 2: Translate**
+
+Create another file with updated translations (in the same order as the source file). For this you can use the [Google Translator Toolkit](https://translate.google.com/toolkit) or [Bing Translator](http://www.bing.com/translator/).
+
+**Step 3: Import your translations**
+
+ $ bench update-translations [lang] [source path] [translated path]
+
+**Step 4: Update `languages.txt`**
+
+Add your language in `apps/languages.txt` and also `frappe/data/languages.txt` (fore new bench installs)
+
+**Step 5: Commit each app and push**
+
+A new file will be added to the `translations` folder in each app. You need to add that file and push to your repo. Then send us a pull-request.
+
+---
+
diff --git a/frappe/docs/user/guides/basics/writing-tests.md b/frappe/docs/user/guides/basics/writing-tests.md
new file mode 100644
index 0000000000..f151416ccd
--- /dev/null
+++ b/frappe/docs/user/guides/basics/writing-tests.md
@@ -0,0 +1,109 @@
+# Writing Tests
+
+### Introduction
+
+Frappe provides some basic tooling to quickly write automated tests. There are some basic rules:
+
+1. Test can be anywhere in your repository but must begin with `test_` and should be a `.py` file.
+1. Tests must run on a site that starts with `test_`. This is to prevent accidental loss of data.
+1. Test stubs are automatically generated for new DocTypes.
+1. Frappe test runner will automatically build test records for dependant DocTypes identified by the `Link` type field (Foreign Key)
+1. Tests can be executed using `bench run-tests`
+1. For non-DocType tests, you can write simple unittests and prefix your file names with `test_`.
+
+### Tests for a DocType
+
+#### Writing DocType Tests:
+
+1. Records that are used for testing are stored in a file `test_records.json` in the doctype folder. [For example see the Event Tests](https://github.com/frappe/frappe/blob/develop/frappe/core/doctype/event/test_records.json).
+1. Test cases are in a file named `test_[doctype].py`
+1. To provide the test records (and dependencies) call `test_records = frappe.get_test_records('Event')` in your test case file.
+
+#### Example (for `test_records.json`):
+
+ [
+ {
+ "doctype": "Event",
+ "subject":"_Test Event 1",
+ "starts_on": "2014-01-01",
+ "event_type": "Public"
+ },
+ {
+ "doctype": "Event",
+ "starts_on": "2014-01-01",
+ "subject":"_Test Event 2",
+ "event_type": "Private"
+ },
+ {
+ "doctype": "Event",
+ "starts_on": "2014-01-01",
+ "subject":"_Test Event 3",
+ "event_type": "Private",
+ "event_individuals": [{
+ "person": "test1@example.com"
+ }]
+ }
+ ]
+
+
+#### Example (for `test_event.py`):
+
+ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
+ # MIT License. See license.txt
+
+ import frappe
+ import frappe.defaults
+ import unittest
+
+ # load test records and dependencies
+ test_records = frappe.get_test_records('Event')
+
+ class TestEvent(unittest.TestCase):
+ def tearDown(self):
+ frappe.set_user("Administrator")
+
+ def test_allowed_public(self):
+ frappe.set_user("test1@example.com")
+ doc = frappe.get_doc("Event", frappe.db.get_value("Event", {"subject":"_Test Event 1"}))
+ self.assertTrue(frappe.has_permission("Event", doc=doc))
+
+ def test_not_allowed_private(self):
+ frappe.set_user("test1@example.com")
+ doc = frappe.get_doc("Event", frappe.db.get_value("Event", {"subject":"_Test Event 2"}))
+ self.assertFalse(frappe.has_permission("Event", doc=doc))
+
+ def test_allowed_private_if_in_event_user(self):
+ frappe.set_user("test1@example.com")
+ doc = frappe.get_doc("Event", frappe.db.get_value("Event", {"subject":"_Test Event 3"}))
+ self.assertTrue(frappe.has_permission("Event", doc=doc))
+
+ def test_event_list(self):
+ frappe.set_user("test1@example.com")
+ res = frappe.get_list("Event", filters=[["Event", "subject", "like", "_Test Event%"]], fields=["name", "subject"])
+ self.assertEquals(len(res), 2)
+ subjects = [r.subject for r in res]
+ self.assertTrue("_Test Event 1" in subjects)
+ self.assertTrue("_Test Event 3" in subjects)
+ self.assertFalse("_Test Event 2" in subjects)
+
+#### Running Tests
+
+To run a test for a doctype
+
+ bench run-tests --doctype [doctype]
+
+This function will build all the test dependencies and run your tests.
+
+### Running All Tests
+
+To run all tests:
+
+ bench run-tests
+
+---
+
+## Client Side Testing (Using Selenium)
+
+> This feature is still under development.
+
+For an example see, [https://github.com/frappe/erpnext/blob/develop/erpnext/tests/sel_tests.py](https://github.com/frappe/erpnext/blob/develop/erpnext/tests/sel_tests.py)
diff --git a/frappe/docs/user/guides/data/import-large-csv-file.md b/frappe/docs/user/guides/data/import-large-csv-file.md
new file mode 100644
index 0000000000..5194ebd98d
--- /dev/null
+++ b/frappe/docs/user/guides/data/import-large-csv-file.md
@@ -0,0 +1,23 @@
+To import very large CSV files, you can use the bench utility `import-csv`.
+
+The benefit is that this is not subject to timeouts if you use the web interface.
+
+Here is an example:
+
+ bench --site test.erpnext.com import-csv ~/Downloads/Activity_Type.csv
+
+### Help
+
+ $ bench import-csv --help
+ Usage: bench import-csv [OPTIONS] PATH
+
+ Import CSV using data import tool
+
+ Options:
+ --only-insert Do not overwrite existing records
+ --submit-after-import Submit document after importing it
+ --ignore-encoding-errors Ignore encoding errors while coverting to unicode
+ --help Show this message and exit.
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/user/guides/data/index.md b/frappe/docs/user/guides/data/index.md
new file mode 100644
index 0000000000..e6f341b236
--- /dev/null
+++ b/frappe/docs/user/guides/data/index.md
@@ -0,0 +1,3 @@
+# Data Management
+
+{index}
diff --git a/frappe/docs/user/guides/data/index.txt b/frappe/docs/user/guides/data/index.txt
new file mode 100644
index 0000000000..4794a002bc
--- /dev/null
+++ b/frappe/docs/user/guides/data/index.txt
@@ -0,0 +1 @@
+import-large-csv-file
diff --git a/frappe/docs/user/guides/deployment/checking-problems-in-bench.md b/frappe/docs/user/guides/deployment/checking-problems-in-bench.md
new file mode 100644
index 0000000000..05fcd3d879
--- /dev/null
+++ b/frappe/docs/user/guides/deployment/checking-problems-in-bench.md
@@ -0,0 +1,15 @@
+
+
+If you're experiencing delays in scheduled jobs or they don't seem to run, you run run the following command to diagnose the issue.
+
+`bench doctor`
+
+A desirable output is like below
+
+
+ Workers online: True
+ Pending tasks 0
+ Timed out locks:
+
+
+We'll be adding more health checks soon.
diff --git a/frappe/docs/user/guides/deployment/configuring-https.md b/frappe/docs/user/guides/deployment/configuring-https.md
new file mode 100644
index 0000000000..4fb90be226
--- /dev/null
+++ b/frappe/docs/user/guides/deployment/configuring-https.md
@@ -0,0 +1,43 @@
+
+### Get the required files
+
+You can buy a SSL certificate from a trusted Certificate Authority or generate your own. For self signed certificates the browser will show a warning that the certificate is not trusted.
+
+The files required are
+
+* Certificate (usually with extension .crt)
+* Decrypted private key
+
+If you have multiple certificates (primary and intermediate), you will have to concatenate them. For example,
+
+ cat your_certificate.crt CA.crt >> certificate_bundle.crt
+
+Also make sure that your private key is not world readable. Generally, it is owned and readable only by root
+
+ chown root private.key
+ chmod 600 private.key
+
+### Move the two files to an appropriate location
+
+ mkdir /etc/nginx/conf.d/ssl
+ mv private.key /etc/nginx/conf.d/ssl/private.key
+ mv certificate_bundle.crt /etc/nginx/conf.d/ssl/certificate_bundle.crt
+
+### Setup nginx config
+
+Set the paths to the certificate and private key for your site
+
+ bench set-ssl-certificate site1.local /etc/nginx/ssl/certificate_bundle.crt
+ bench set-ssl-key site1.local /etc/nginx/ssl/private.key
+
+### Generate nginx config
+
+ bench setup nginx
+
+### Reload nginx
+
+ service nginx reload
+
+or
+
+ systemctl reload nginx # for CentOS 7
\ No newline at end of file
diff --git a/frappe/docs/user/guides/deployment/email-notifications-for-failed-background-jobs.md b/frappe/docs/user/guides/deployment/email-notifications-for-failed-background-jobs.md
new file mode 100644
index 0000000000..3c582762ec
--- /dev/null
+++ b/frappe/docs/user/guides/deployment/email-notifications-for-failed-background-jobs.md
@@ -0,0 +1,23 @@
+
+
+Frappe handles failure of jobs in the following way,
1) If a job fails, (raises exception), it's logged in Scheduler Log and logs/worker.error.log. 2) Keeps a lock file and would not run anymore if lock file is there. 3) Raises LockTimeoutError in case the lock file is more than 10 minutes old.
+
+You can configure email notification for scheduler errors. By writing a file, sites/common_site_config.json with content
+
+{
+ "celery_error_emails ": {
+ "ADMINS ": [
+ [
+ "Person 1" ,
+ "person1@example.com"
+ ],
+ [
+ "Person2 " ,
+ "person2@example.com"
+ ]
+ ] ,
+ "SERVER_EMAIL ": "exceptions@example.com"
+ }
+ }
+
+One limitation is that it'll use local mailserver on port 25 to send the emails.
\ No newline at end of file
diff --git a/frappe/docs/user/guides/deployment/how-to-change-host-name-from-localhost.md b/frappe/docs/user/guides/deployment/how-to-change-host-name-from-localhost.md
new file mode 100644
index 0000000000..39d0008ec8
--- /dev/null
+++ b/frappe/docs/user/guides/deployment/how-to-change-host-name-from-localhost.md
@@ -0,0 +1,18 @@
+While using a virtual machine, links within emails will be point to your host, e.g. localhost, like **http://localhost/set-password** etc.
+
+Frappe will automatically extract the host name from the incoming request, or from the `host_name` property from `site_config`.
+
+### bench set-config
+
+To fix this, you can use **bench set-config** to set your public IP or domain name as the host name.
+
+#### Example:
+
+ bench --site mysite.com set-config host_name mysite.com
+
+---
+
+Or edit the `frappe-bench/sites/mysite.com/site_config.json` and add a `host_name` property.
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/user/guides/deployment/how-to-enable-social-logins.md b/frappe/docs/user/guides/deployment/how-to-enable-social-logins.md
new file mode 100644
index 0000000000..847cf78ea3
--- /dev/null
+++ b/frappe/docs/user/guides/deployment/how-to-enable-social-logins.md
@@ -0,0 +1,67 @@
+Use Facebook, Google or GitHub authentication to login to Frappe, and your users will be spared from remembering another password.
+
+The system uses the **Email ID** supplied by these services to **match with an existing user** in Frappe. If no such user is found, **a new user is created** of the default type **Website User**, if Signup is not disabled in Website Settings. Any System Manager can later change the user type from **Website User** to **System User**, so that the user can access the Desktop.
+
+
+
+ Login screen with Social Logins enabled
+
+
+To enable these signups, you need to have **Client ID** and **Client Secret** from these authentication services for your Frappe site. The Client ID and Client Secret are to be set in Website > Setup > Social Login Keys. Here are the steps to obtain these credentials.
+
+> Use **https://{{ yoursite }}** if your site is HTTPS enabled.
+
+---
+
+### Facebook
+
+1. Go to [https://developers.facebook.com](https://developers.facebook.com)
+1. Click on Apps (topbar) > New App, fill in the form.
+1. Go to Settings > Basic, set the **Contact Email** and save the changes.
+1. Go to Settings > Advanced, find the field **Valid OAuth redirect URIs**, and enter:
+ **http://{{ yoursite }}/api/method/frappe.templates.pages.login.login\_via\_facebook**
+1. Save the changes in Advance tab.
+1. Go to Status & Review and switch on "Do you want to make this app and all its live features available to the general public?"
+1. Go to Dashboard, click on the show button besides App Secret, and copy the App ID and App Secret into **Desktop > Website > Setup > Social Login Keys**
+
+
+ VIDEO
+
+
+---
+
+### Google
+
+1. Go to [https://console.developers.google.com](https://console.developers.google.com)
+1. Create a new Project and fill in the form.
+1. Click on APIs & Auth > Credentials > Create new Client ID
+1. Fill the form with:
+ - Web Application
+ - Authorized JavaScript origins as **http://{{ yoursite }}**
+ - Authorized redirect URI as
+ **http://{{ yoursite }}/api/method/frappe.templates.pages.login.login\_via\_google**
+1. Go to the section **Client ID for web application** and copy the Client ID and Client Secret into **Desktop > Website > Setup > Social Login Keys**
+
+
+ VIDEO
+
+
+---
+
+### GitHub
+
+1. Go to [https://github.com/settings/applications](https://github.com/settings/applications)
+1. Click on **Register new application**
+1. Fill the form with:
+ - Homepage URL as **http://{{ yoursite }}**
+ - Authorization callback URL as
+ **http://{{ yoursite }}/api/method/frappe.templates.pages.login.login\_via\_github**
+1. Click on Register application.
+1. Copy the generated Client ID and Client Secret into **Desktop > Website > Setup > Social Login Keys**
+
+
+ VIDEO
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/user/guides/deployment/how-to-migrate-doctype-changes-to-production.md b/frappe/docs/user/guides/deployment/how-to-migrate-doctype-changes-to-production.md
new file mode 100644
index 0000000000..35a15645ab
--- /dev/null
+++ b/frappe/docs/user/guides/deployment/how-to-migrate-doctype-changes-to-production.md
@@ -0,0 +1,13 @@
+#### 1. DocType / Schema Changes
+
+If you are in `developer_mode`, the `.json` files for each **DocType** are automatically updated.
+
+When you update in your production using `--latest` or `bench update`, these changes are updated in the site's schema too!
+
+#### 2. Permissions
+
+Permissions do not get updated because the user may have changed them. To update permissions, you can add a new patch in the `patches.txt` of your app.
+
+ execute:frappe.permissions.reset_perms("[docype]")
+
+
\ No newline at end of file
diff --git a/frappe/docs/user/guides/deployment/index.md b/frappe/docs/user/guides/deployment/index.md
new file mode 100644
index 0000000000..9487bbf803
--- /dev/null
+++ b/frappe/docs/user/guides/deployment/index.md
@@ -0,0 +1,5 @@
+# Deployment
+
+Deploying your apps on remote servers
+
+{index}
diff --git a/frappe/docs/user/guides/deployment/index.txt b/frappe/docs/user/guides/deployment/index.txt
new file mode 100644
index 0000000000..bf719dcf09
--- /dev/null
+++ b/frappe/docs/user/guides/deployment/index.txt
@@ -0,0 +1,7 @@
+migrations
+how-to-migrate-doctype-changes-to-production
+how-to-change-host-name-from-localhost
+configuring-https
+checking-problems-in-bench
+email-notifications-for-failed-background-jobs
+how-to-enable-social-logins
diff --git a/frappe/docs/user/guides/deployment/migrations.md b/frappe/docs/user/guides/deployment/migrations.md
new file mode 100644
index 0000000000..c40a2a7c4b
--- /dev/null
+++ b/frappe/docs/user/guides/deployment/migrations.md
@@ -0,0 +1,69 @@
+# Migrations
+
+A project often undergoes changes related to database schema during course of
+its life. It may also be required patch existing data. Frappe bundles tools to
+handle these schenarios.
+
+When you pull updates from any Frappe app (including Frappe), you should run
+`bench migrate` to apply schema changes and data migrations if any.
+
+## Schema changes
+
+You can edit a DocType to add, remove or change fields. On saving a DocType,
+a JSON file containing the DocType data is added to source tree of your app.
+When you add an app to a site, the DocTypes are installed using this JSON file.
+For making schema changes, it's required to set `developer_mode` in the
+configuration.
+
+On running a sync (`bench migrate`), doctypes in the system are synced to
+their latest version from the JSON files in the app.
+
+Note: Fields are soft deleted ie. the columns are not removed from the database
+table and however, they will not be visible in the documents. This is done to
+avoid any potential data loss situations and to allow you write related data
+migrations which might need values from deleted fields.
+
+Note: Frappe doesn't support reverse schema migrations.
+
+## Data Migrations
+
+On introducing data related changes, you might want to run one off scripts to
+change existing data to match expectations as per new code.
+
+To add a data migration to your code, you will have to write an `execute`
+function to a python module and add it to `patches.txt` of your app.
+
+It is recommended to make a file with a patch number and name in its path and
+add it to a patches package (directory) in your app. You can then add a line
+with dotted path to the patch module to `patches.txt`.
+
+The directory structure followed in Frappe is as below
+
+
+ frappe
+ └── patches
+ └── 4_0
+ └── my_awesome_patch.py
+
+The patch can be added to `patches.txt` by adding a line like
+
+ frappe.patches.4_0.my_awesome_patch
+
+The metadata ie. DocType available in the execute function will be the latest as
+per JSON files in the apps. However, you will not be able to access metadata of
+any previous states of the system.
+
+#### One off Python statements
+
+You can also add one off python statements in `patches.txt` using the syntax,
+ execute:{python statement}
+
+For example,
+ execute:frappe.get_doc("User", "Guest").save()
+
+Note: All lines in patches.txt have to be unique. If you want to run a line
+twice, you can make it unique by adding a distinct comment.
+
+For Example,
+
+ execute:frappe.installer.make_site_dirs() #2014-02-19
diff --git a/frappe/docs/user/guides/index.md b/frappe/docs/user/guides/index.md
new file mode 100644
index 0000000000..9eeed8baa8
--- /dev/null
+++ b/frappe/docs/user/guides/index.md
@@ -0,0 +1,7 @@
+# Guides
+
+The Frappe Framework is a server side and client side framework and is built with the philosophy make it a "battries included" framework. It has libraries and API for everything from authentication to reports.
+
+In this section we will try and cover the most commonly used API on client and server side that will be useful for app development.
+
+{index}
diff --git a/frappe/docs/user/guides/index.txt b/frappe/docs/user/guides/index.txt
new file mode 100644
index 0000000000..d47785065a
--- /dev/null
+++ b/frappe/docs/user/guides/index.txt
@@ -0,0 +1,7 @@
+basics
+app-development
+deployment
+reports-and-printing
+portal-development
+data
+integration
diff --git a/frappe/docs/user/guides/integration/index.md b/frappe/docs/user/guides/integration/index.md
new file mode 100644
index 0000000000..b97815866a
--- /dev/null
+++ b/frappe/docs/user/guides/integration/index.md
@@ -0,0 +1,3 @@
+# Integrations
+
+{index}
diff --git a/frappe/docs/user/guides/integration/index.txt b/frappe/docs/user/guides/integration/index.txt
new file mode 100644
index 0000000000..8f8d276e69
--- /dev/null
+++ b/frappe/docs/user/guides/integration/index.txt
@@ -0,0 +1 @@
+rest_api
diff --git a/frappe/docs/user/guides/integration/rest_api.md b/frappe/docs/user/guides/integration/rest_api.md
new file mode 100644
index 0000000000..7f28f82b38
--- /dev/null
+++ b/frappe/docs/user/guides/integration/rest_api.md
@@ -0,0 +1,283 @@
+# REST API
+
+Frappe ships with an HTTP API. There are two parts of this API.
+
+1. Remote Procedure Calls (RPC)
+2. REST
+
+## 1. RPC
+
+A request to an endpoint `/api/method/{dotted.path.to.function}` will call
+a whitelisted python function. A function can be whitelisted using the
+`frappe.whitelist` decorator.
+
+For example, Add the following to sample\_app/\_\_init\_\_.py
+
+ @frappe.whitelist(allow_guest=True)
+ def ping():
+ return 'pong'
+
+GET http://frappe.local:8000**/api/method/sample_app.ping**
+
+_Response:_
+
+ {
+ "message": "pong"
+ }
+
+
+## 2. REST
+
+All documents in Frappe are available via a RESTful API with prefix
+`/api/resource/`.
+
+### Login
+
+To login, you will have to send a POST request to the login method.
+
+POST http://frappe.local:8000**/api/method/login**
+
+ usr=Administrator&pwd=admin
+
+_Response:_
+
+ {
+ "full_name": "Administrator",
+ "message": "Logged In"
+ }
+
+
+Try to make an authenticated request
+
+GET http://frappe.local:8000**/api/method/frappe.auth.get\_logged\_user**
+
+_Response:_
+
+ {
+ "message": "Administrator"
+ }
+
+
+### Listing Documents
+
+To list documents, the URL endpoint is `/api/resource/{doctype}` and the
+expected HTTP verb is GET.
+
+Response is returned as JSON Object and the listing is an array in with the key `data`.
+
+GET http://frappe.local:8000**/api/resource/Person**
+
+_Response:_
+
+ {
+ "data": [
+ {
+ "name": "000000012"
+ },
+ {
+ "name": "000000008"
+ }
+ ]
+ }
+
+
+#### Fields
+
+By default, only name field is included in the listing, to add more fields, you
+can pass the fields param to GET request. The param has to be a JSON array.
+
+GET http://frappe.local:8000**/api/resource/Person/?fields=["name", "first\_name"]**
+
+_Response:_
+
+ {
+ "data": [
+ {
+ "first_name": "Jane",
+ "name": "000000012"
+ },
+ {
+ "first_name": "John",
+ "name": "000000008"
+ }
+ ]
+ }
+
+
+#### Filters
+
+You can filter the listing using sql conditions by passing them as the `filters`
+GET param. Each condition is an array of the format, [{doctype}, {field},
+{operator}, {operand}].
+
+Eg, to filter persons with name Jane, pass a param `filters=[["Person", "first_name", "=", "Jane"]]`
+
+GET http://frappe.local:8000**/api/resource/Person/**
+
+_Response:_
+ {
+ "data": [
+ {
+ "name": "000000012"
+ }
+ ]
+ }
+
+
+#### Pagination
+
+All listings are returned paginated by 20 items. To change the page size, you
+can pass `limit_page_length`. To request succesive pages, pass `limit_start` as
+per your `limit_page_length`.
+
+For Example, to request second page, pass `limit_start` as 20.
+
+GET http://frappe.local:8000**/api/resource/DocType**
+
+_Response:_
+
+ {
+ "data": [
+ {
+ "name": "testdoc"
+ },
+ {
+ "name": "Person"
+ },
+
+ ......
+
+ {
+ "name": "Website Template"
+ }
+ ]
+ }
+
+
+GET http://frappe.local:8000**/api/resource/DocType?limit_start=20**
+
+_Response:_
+
+ {
+ "data": [
+ {
+ "name": "Website Route"
+ },
+ {
+ "name": "Version"
+ },
+ {
+ "name": "Blog Post"
+ },
+
+ ......
+
+ {
+ "name": "Custom Field"
+ }
+ ]
+ }
+
+
+### CRUD
+
+#### Create
+
+You can create a document by sending a `POST` request to the url, `/api/resource/{doctype}`.
+
+POST http://frappe.local:8000**/api/resource/Person**
+
+_Body_:
+
+ data={"first_name": "Robert"}
+
+_Response:_
+
+ {
+ "data": {
+ "first_name": "Robert",
+ "last_name": null,
+ "modified_by": "Administrator",
+ "name": "000000051",
+ "parent": null,
+ "creation": "2014-05-04 17:22:38.037685",
+ "modified": "2014-05-04 17:22:38.037685",
+ "doctype": "Person",
+ "idx": null,
+ "parenttype": null,
+ "owner": "Administrator",
+ "docstatus": 0,
+ "parentfield": null
+ }
+ }
+
+#### Read
+
+You can get a document by its name using the url, `/api/resource/{doctype}/{name}`
+
+For Example,
+
+GET http://frappe.local:8000**/api/resource/Person/000000012**
+
+_Response:_
+
+ {
+ "data": {
+ "first_name": "Jane",
+ "last_name": "Doe",
+ "modified_by": "Administrator",
+ "name": "000000012",
+ "parent": null,
+ "creation": "2014-04-25 17:56:51.105372",
+ "modified": "2014-04-25 17:56:51.105372",
+ "doctype": "Person",
+ "idx": null,
+ "parenttype": null,
+ "owner": "Administrator",
+ "docstatus": 0,
+ "parentfield": null
+ }
+ }
+
+### Update
+
+You can create a document by sending a `PUT` request to the url,
+`/api/resource/{doctype}`. This acts like a `PATCH` HTTP request in which you do
+not have to send the whole document but only the parts you want to change.
+
+For Example,
+
+PUT http://frappe.local:8000**/api/resource/Person/000000008**
+
+_Body:_
+
+ data={"last_name": "Watson"}
+
+_Response:_
+
+ {
+ "data": {
+ "first_name": "John ",
+ "last_name": "Watson",
+ "modified_by": "Administrator",
+ "name": "000000008",
+ "creation": "2014-04-25 17:26:22.728327",
+ "modified": "2014-05-04 18:21:45.385995",
+ "doctype": "Person",
+ "owner": "Administrator",
+ "docstatus": 0
+ }
+ }
+
+### Delete
+
+You can delete a document by its name by sending a `DELETE` request to the url,
+`/api/resource/{doctype}/{name}`.
+
+For Example,
+
+DELETE http://frappe.local:8000**/api/resource/Person/000000008**
+
+_Response:_
+
+ {"message":"ok"}
diff --git a/frappe/docs/user/guides/portal-development/.md b/frappe/docs/user/guides/portal-development/.md
new file mode 100644
index 0000000000..9136f09c29
--- /dev/null
+++ b/frappe/docs/user/guides/portal-development/.md
@@ -0,0 +1,5 @@
+# Pages
+
+You can make your website by adding pages to the `/www` folder of your website. The urls of your site will match the path of your pages within the `/www` folder.
+
+Pages must be `.html` or `.md` (Markdown) files. Basic HTML template is provided in frappe in `frappe/templates/base_template.html`
diff --git a/frappe/docs/user/guides/portal-development/adding-pages.md b/frappe/docs/user/guides/portal-development/adding-pages.md
new file mode 100644
index 0000000000..c8bdd53552
--- /dev/null
+++ b/frappe/docs/user/guides/portal-development/adding-pages.md
@@ -0,0 +1,39 @@
+# Adding Pages
+
+To add pages, just add `.html` or `.md` files in the `www` folder. The pages must only have the content, not the `` and `` tags.
+
+You can also write markdown pages
+
+### Index
+
+The first file in a folder must be called `index.md` or `index.html`
+
+Either file must be present for the system to make this a valid folder to build pages.
+
+### Markdown
+
+ # This is a title
+
+ This is some page content
+ a [link](/link/to/page)
+
+### Adding Links
+
+Links urls to pages can be given without the `.html` extension for example `/home/link`
+
+### Title
+
+The first `` block if present will be the page title if not specified in a special tag. If no `` or title is specified, the file name will be the title.
+
+### Adding CSS
+
+You can also add a `.css` file with the same filename (e.g. `index.css` for `index.md`) that will be rendered with the page.
+
+### Special Tags
+
+1. `` will make the page render in Jinja
+2. `` will add a custom title
+3. `` will not add breadcrumbs in the page
+4. `` will enable caching (if you have used Jinja templating)
+
+{next}
diff --git a/frappe/docs/user/guides/portal-development/building.md b/frappe/docs/user/guides/portal-development/building.md
new file mode 100644
index 0000000000..1e7ca23c9a
--- /dev/null
+++ b/frappe/docs/user/guides/portal-development/building.md
@@ -0,0 +1,15 @@
+# Building the site
+
+To make the pages to be served on the web, they must first be synced with the database. This is done by running:
+
+ bench --site sitename sync-www
+
+To re-build the site
+
+ bench --site sitename --force sync-www
+
+Clearing the website cache
+
+ bench --site sitename clear-website-cache
+
+{next}
diff --git a/frappe/docs/user/guides/portal-development/contents.md b/frappe/docs/user/guides/portal-development/contents.md
new file mode 100644
index 0000000000..c2ebaf5551
--- /dev/null
+++ b/frappe/docs/user/guides/portal-development/contents.md
@@ -0,0 +1,17 @@
+# Table of Contents
+
+You can add a table of contents by adding `{index}` string on a new line.
+
+You can also make Previous and Next buttons by adding `previous` or `next` in `{}`
+
+### Showing contents
+
+ # This is a title
+
+ Hello paragraph
+
+ ### Contents:
+
+ {index}
+
+{next}
diff --git a/frappe/docs/user/guides/portal-development/context.md b/frappe/docs/user/guides/portal-development/context.md
new file mode 100644
index 0000000000..5c72a1835b
--- /dev/null
+++ b/frappe/docs/user/guides/portal-development/context.md
@@ -0,0 +1,8 @@
+# Adding to context
+
+You can add more data for the pages by adding a `.py` file with the same filename (e.g. `index.py` for `index.md`) with a `get_context` method.
+
+ def get_context(context):
+ context.data = frappe.db.sql("some query")
+
+{next}
diff --git a/frappe/docs/user/guides/portal-development/index.md b/frappe/docs/user/guides/portal-development/index.md
new file mode 100644
index 0000000000..348e7cf9e5
--- /dev/null
+++ b/frappe/docs/user/guides/portal-development/index.md
@@ -0,0 +1,7 @@
+# Making Portals
+
+You can make your website by adding pages to the `/www` folder of your website. The urls of your site will match the path of your pages within the `/www` folder.
+
+Pages must be `.html` or `.md` (Markdown) files. Basic HTML template is provided in frappe in `frappe/templates/base_template.html`
+
+{index}
diff --git a/frappe/docs/user/guides/portal-development/index.txt b/frappe/docs/user/guides/portal-development/index.txt
new file mode 100644
index 0000000000..3eeece6502
--- /dev/null
+++ b/frappe/docs/user/guides/portal-development/index.txt
@@ -0,0 +1,5 @@
+adding-pages
+ordering
+contents
+context
+building
diff --git a/frappe/docs/user/guides/portal-development/ordering.md b/frappe/docs/user/guides/portal-development/ordering.md
new file mode 100644
index 0000000000..76db949fbb
--- /dev/null
+++ b/frappe/docs/user/guides/portal-development/ordering.md
@@ -0,0 +1,13 @@
+# Ordering
+
+You can defining the ordering of pages in index by defining the index.txt file in your folder. The index.txt file must have the names (without extensions) of the pages in that folder indicating the order.
+
+For example for this folder the `index.txt` looks like:
+
+ adding-pages
+ ordering
+ contents
+ context
+ building
+
+{next}
diff --git a/frappe/docs/user/guides/reports-and-printing/getting-information-from-another-document-in-print-format.md b/frappe/docs/user/guides/reports-and-printing/getting-information-from-another-document-in-print-format.md
new file mode 100644
index 0000000000..321028d7af
--- /dev/null
+++ b/frappe/docs/user/guides/reports-and-printing/getting-information-from-another-document-in-print-format.md
@@ -0,0 +1,7 @@
+In a print format, you can get data from another document. For example in if you have a fields called `sales_order` in Sales Invoice, then you can get the sales order details using `frappe.get_doc`:
+
+{% raw %}
+ {% set sales_order_doc = frappe.get_doc("Sales Order", sales_order) %}
+
+ {{ sales_order_doc.customer }}
+{% endraw %}
diff --git a/frappe/docs/user/guides/reports-and-printing/how-to-make-query-report.md b/frappe/docs/user/guides/reports-and-printing/how-to-make-query-report.md
new file mode 100644
index 0000000000..92ea7d4b2e
--- /dev/null
+++ b/frappe/docs/user/guides/reports-and-printing/how-to-make-query-report.md
@@ -0,0 +1,56 @@
+You can create tabulated reports using complex SQL queries by creating a new Report. These reports can be created by a System Manager and are stored in the Database
+
+> Note: You will need System Manager Permissions for this.
+
+To create a new Query Report:
+
+### 1. Create a new Report
+
+
+
+1. Set type as "Query Report"
+1. Set the reference DocType - Users that have access to the reference DocType will have access to the report
+1. Set the module - The report will appear in the "Custom Reports" section of the module.
+1. Add your Query
+
+### 2. Set the Query
+
+You can define complex queries such as:
+
+
+ SELECT
+ `tabProduction Order`.name as "Production Order:Link/Production Order:200",
+ `tabProduction Order`.creation as "Date:Date:120",
+ `tabProduction Order`.production_item as "Item:Link/Item:150",
+ `tabProduction Order`.qty as "To Produce:Int:100",
+ `tabProduction Order`.produced_qty as "Produced:Int:100"
+ FROM
+ `tabProduction Order`
+ WHERE
+ `tabProduction Order`.docstatus=1
+ AND ifnull(`tabProduction Order`.produced_qty,0) < `tabProduction Order`.qty
+ AND EXISTS (SELECT name from `tabStock Entry` where production_order =`tabProduction Order`.name)
+
+1. To format the columns, set labels for each column in the format: [Label]:[Field Type]/[Options]:[Width]
+
+### 3. Check the Report
+
+
+
+### 4. Advanced (adding filters)
+
+If you are making a standard report, you can add filters in your query report just like [script reports](https://frappe.io/kb/reports/how-to-make-script-reports) by adding a `.js` file in your query report folder. To include filters in your query, use `%(filter_key)s` where your filter value will be shown.
+
+For example
+
+ SELECT ... FROM ... WHERE item_code = %(item_code)s ORDER BY ...
+
+---
+
+### Note: Standard Script Report
+
+If you are developing a standard report for an app, make sure to set "Is Standard" as "Yes"
+
+
+
+
\ No newline at end of file
diff --git a/frappe/docs/user/guides/reports-and-printing/how-to-make-script-reports.md b/frappe/docs/user/guides/reports-and-printing/how-to-make-script-reports.md
new file mode 100644
index 0000000000..4f097b34d5
--- /dev/null
+++ b/frappe/docs/user/guides/reports-and-printing/how-to-make-script-reports.md
@@ -0,0 +1,51 @@
+# Script Report
+
+You can create tabulated reports using server side scripts by creating a new Report.
+
+> Note: You will need Administrator Permissions for this.
+
+Since these reports give you unrestricted access via Python scripts, they can only be created by Administrators. The script part of the report becomes a part of the repository of the application. If you have not created an app, [read this](/developers/guide).
+
+> Note: You must be in [Developer Mode](/developers/how-to/enable-developer-mode) to do this
+
+### 1. Create a new Report
+
+
+
+1. Set Report Type as "Script Report"
+1. Set "Is Standard" as "Yes"
+1. Select the Module in which you want to add this report
+1. In the module folder (for example if it is Accounts in ERPnext the folder will be `erpnext/accounts/report/[report-name]`) you will see that templates for the report files will be created.
+1. In the `.js` file, you can set filters for the reports
+1. In the `.py` file, you can write the script that will generate the report
+
+### 2. Add Filters
+
+You can add filters in the `.js`. See an example below:
+
+ frappe.query_reports["Accounts Receivable"] = {
+ "filters": [
+ {
+ "fieldname":"company",
+ "label": __("Company"),
+ "fieldtype": "Link",
+ "options": "Company",
+ "default": frappe.defaults.get_user_default("company")
+ },
+ ]
+ }
+
+1. These properties are the same as you would set in a DocField in a DocType
+
+### 3. Add the Script
+
+In the `.py` file you can add the script for generating the report.
+
+1. In the `execute` method, two lists `columns` and `data` are returned
+2. Columns must be a list of labels in the same format as query report. **[Label]:[Field Type]/[Options]:[Width]**. For example `Item:Link/Item:150`
+3. You can use all server side modules to build your report.
+4. For example see existing reports. ([Balance Sheet](https://github.com/frappe/erpnext/blob/develop/erpnext/accounts/report/balance_sheet/balance_sheet.py))
+
+### 4. Commit and Push the app
+
+Don't forget to commit and push your app.
diff --git a/frappe/docs/user/guides/reports-and-printing/index.md b/frappe/docs/user/guides/reports-and-printing/index.md
new file mode 100644
index 0000000000..8c464f691c
--- /dev/null
+++ b/frappe/docs/user/guides/reports-and-printing/index.md
@@ -0,0 +1 @@
+# Reports and Printing
diff --git a/frappe/docs/user/guides/reports-and-printing/index.txt b/frappe/docs/user/guides/reports-and-printing/index.txt
new file mode 100644
index 0000000000..ec34e2b102
--- /dev/null
+++ b/frappe/docs/user/guides/reports-and-printing/index.txt
@@ -0,0 +1,5 @@
+how-to-make-script-reports
+how-to-make-query-report
+getting-information-from-another-document-in-print-format
+where-do-i-find-standard-print-formats
+print-format-for-reports
diff --git a/frappe/docs/user/guides/reports-and-printing/print-format-for-reports.md b/frappe/docs/user/guides/reports-and-printing/print-format-for-reports.md
new file mode 100644
index 0000000000..dd582169c0
--- /dev/null
+++ b/frappe/docs/user/guides/reports-and-printing/print-format-for-reports.md
@@ -0,0 +1,70 @@
+# Report Print Formats
+
+In version 4.1 we introduce Report Print Formats. These are HTML templates that you can use to format Query Report data for printing.
+
+### 1. Creating New Print Formats
+
+To create a new Print Format, just drop in a `.html` file in the folder of the query report. For example, for the [General Ledger](https://github.com/frappe/erpnext/tree/develop/erpnext/accounts/report/general_ledger) report in ERPNext, you can drop in a file called `general_ledger.html` along side the `.js` and `.py` files.
+
+##### Tree Of `erpnext/accounts/general_ledger`
+
+ general_ledger/
+ ├── __init__.py
+ ├── general_ledger.html
+ ├── general_ledger.js
+ ├── general_ledger.json
+ └── general_ledger.py
+
+
+### 2. Templating
+
+For templating, we use an adapted version of [John Resig's microtemplating script](http://ejohn.org/blog/javascript-micro-templating/). If you know Javascript, it is very easy to follow this templating language.
+
+##### Here are some examples (from John Resig's Blog):
+
+Example: Properities:
+
+ ">
+
+
+
+
+
+
+Example: Code structures, Loops
+
+ <% for ( var i = 0; i < users.length; i++ ) { %>
+ <%=users[i].name%>
+ <% } %>
+
+> **Note**: It is important to note that you should not use single quotes (') in your template as the engine cannot handle them effectively.
+
+### 3. Data
+
+Data is available to the template as:
+
+- `data`: this is a list of records, with each record as an object with slugified properties from labels. For example "Posting Date" becomes "posting_date"
+- `filters`: filters set in the report
+- `report`: reportview object
+
+### 4. Example
+
+Here is how the General Ledger Report is built:
+
+[General Ledger Print Format Template](https://github.com/frappe/erpnext/blob/develop/erpnext/accounts/report/general_ledger/general_ledger.html)
+
+Here is what the report looks like:
+
+
+
+##### Comments:
+
+1. [Bootstrap Stylesheet](http://getbootstrap.com) is pre-loaded.
+1. You can use all global functions like `fmt_money` and dateutil.
+1. Translatable strings should be written as `__("text")`
+1. You can create modules and import using `{% include "templates/includes/formats/common_format" %}`
+
+
\ No newline at end of file
diff --git a/frappe/docs/user/guides/reports-and-printing/where-do-i-find-standard-print-formats.md b/frappe/docs/user/guides/reports-and-printing/where-do-i-find-standard-print-formats.md
new file mode 100644
index 0000000000..00e351c615
--- /dev/null
+++ b/frappe/docs/user/guides/reports-and-printing/where-do-i-find-standard-print-formats.md
@@ -0,0 +1,40 @@
+Standard Print formats are auto generated from the layout of the DocType. You can customize the standard format by
+
+
+
+1. Customizing Standard Print
+Go to Setup > Customize > Customize Form View and you can:
+
+
+ Re-arranging fields by dragging and dropping
+ Add static elements by adding HTML type fields and adding your HTML in Options
+
+
+ Hiding fields by setting the Print Hide property
+
+
+
+2. Creating new layouts based on Print Formats
+
+As there are not templates that are generated for standard Print Formats, you will have to create new templates from scratch using the Jinja Templating Language via
+Setup > Printing and Branding > Print Format
+
+
+
+ See Print Format help .
+
+
+ You can use the Bootstrap CSS framework to layout your print formats
+
+
+
+
+Tip: You can import Standard Template macros for building your print formats.
+
+
+Example, adding the standard header:
+
+
+{% raw %}{%- from "templates/print_formats/standard_macros.html" import add_header -%}
+{{ add_header() }}{% endraw %}
+
diff --git a/frappe/docs/user/index.md b/frappe/docs/user/index.md
new file mode 100644
index 0000000000..a25785e59e
--- /dev/null
+++ b/frappe/docs/user/index.md
@@ -0,0 +1,3 @@
+# Develop Apps with Frappe
+
+{index}
diff --git a/frappe/docs/user/index.txt b/frappe/docs/user/index.txt
new file mode 100644
index 0000000000..dfc33261aa
--- /dev/null
+++ b/frappe/docs/user/index.txt
@@ -0,0 +1,2 @@
+tutorial
+guides
diff --git a/frappe/docs/user/tutorial/app.md b/frappe/docs/user/tutorial/app.md
new file mode 100644
index 0000000000..e338ce8a17
--- /dev/null
+++ b/frappe/docs/user/tutorial/app.md
@@ -0,0 +1,9 @@
+# What is an Application
+
+An Application in Frappe is just a standard Python application. You can structure a Frappe Application the same way you structure a standard Python Application. For deployment, Frappe uses the standard Python Setuptools, so you can easily port and install the application on any machine.
+
+Frappe Framework provides a WSGI interface and for development you can use the built-in Werkzeug server. For implementing in production, we recommend using nginx and gunicorn.
+
+Frappe also has a multi-tenant architecture, grounds up. This means that you can run multiple "sites" in your setup, each could be serving a different set of applications and users. The database for each site is separate.
+
+{next}
diff --git a/frappe/docs/user/tutorial/before.md b/frappe/docs/user/tutorial/before.md
new file mode 100644
index 0000000000..1902792127
--- /dev/null
+++ b/frappe/docs/user/tutorial/before.md
@@ -0,0 +1,48 @@
+# Before You Start
+
+A list of tools, technologies that will be very helpful for building apps in Frappe.
+
+There are a number of good tutorials online and we found [CodeAcademy](http://www.codecademy.com/) to be the most beautiful ones out there here bunch of lessons you can learn from CodeAcademy
+
+---
+
+#### 1. Python
+
+Server side Frappe is written in Python and its a good idea to [quickly learn Python](http://www.codecademy.com/tracks/python) before you started digging into Frappe. Another good place to learn Python is the [tutorial on docs.python.org](https://docs.python.org/2.7/tutorial/index.html). Note that Frappe uses Python 2.7
+
+To write quality server side code, you must include automatic tests. You can learn the [basics of test driven development here](http://code.tutsplus.com/tutorials/beginning-test-driven-development-in-python--net-30137).
+
+---
+
+#### 2. Databases MariaDB / MySQL
+
+You need to understand the basics of databases, like how to install, login, create new databases, and basic SQL queries. Here is a [very quick introduction to MySQL](https://www.digitalocean.com/community/tutorials/a-basic-mysql-tutorial) or head to [the MariaDB site for a more detailed understanding](https://mariadb.com/kb/en/mariadb/documentation/getting-started/)
+
+---
+
+#### 3. HTML / CSS
+
+If you are building user interfaces, you will need to [learn basic HTML / CSS](http://www.codecademy.com/tracks/web) and the [Boostrap CSS Framework](http://getbootstrap.com)
+
+---
+
+#### 4. Building UI with Javascript and JQuery
+
+To customize forms and create new rich user interfaces, it is best to [learn Javacsript](http://www.codecademy.com/tracks/javascript) and the [popular library JQuery](http://www.codecademy.com/tracks/jquery).
+
+---
+
+#### 5. Customizing Prints and Web pages with Jinja Templating
+
+If you are customizing Print templates, you need to learn the [Jinja Templating language](http://jinja.pocoo.org/). It is an easy way to create dynamic web pages (HTML).
+
+---
+
+#### 6. Git and GitHub
+
+[Learn how to contribute back to an open source project usign Git and GitHub](https://guides.github.com/activities/contributing-to-open-source/), two great tools to help you manage your code and share it with others.
+
+---
+
+When you are ready, [try building a sample application on Frappe]({{ docs_base_url }}/user/tutorial/app)
+
diff --git a/frappe/docs/user/tutorial/bench.md b/frappe/docs/user/tutorial/bench.md
new file mode 100644
index 0000000000..e720d9dc98
--- /dev/null
+++ b/frappe/docs/user/tutorial/bench.md
@@ -0,0 +1,11 @@
+# Installing the Frappe Bench
+
+Easiest way to setup frappe on a Unix Like system is to use frappe-bench. Read the detailed instructions on how to install using Frappe Bench.
+
+> [https://github.com/frappe/bench](https://github.com/frappe/bench)
+
+With Frappe Bench you will be able to setup and host multiple applications and sites and it will also setup a Python Virtualenv so that you can have an isolated environment to run your applications (and will not have version conflict with other development environments).
+
+The `bench` command line tool will also be installed that will help you in development and management of the installation.
+
+{next}
diff --git a/frappe/docs/user/tutorial/conclusion.md b/frappe/docs/user/tutorial/conclusion.md
new file mode 100644
index 0000000000..f45b64ba23
--- /dev/null
+++ b/frappe/docs/user/tutorial/conclusion.md
@@ -0,0 +1,7 @@
+# Conclusion
+
+
+We hope this will give you an overview of how applications are developed in Frappe. The objective was to briefly touch on the various aspects of application development and give a broad overview. To get help on specific issues, look at the API.
+
+For help, join the community at the [chat channel on Gitter](https://gitter.im/frappe/erpnext) or the [developer forum](https://discuss.erpnext.com)
+
diff --git a/frappe/docs/user/tutorial/controllers.md b/frappe/docs/user/tutorial/controllers.md
new file mode 100644
index 0000000000..f994041370
--- /dev/null
+++ b/frappe/docs/user/tutorial/controllers.md
@@ -0,0 +1,59 @@
+# Controllers
+
+Next step would be adding methods and event handlers to models. In your app, we sould like to ensure that if a Library Tranasction is made, the Article in question must be in stock and the member loaning the Article must have a valid membership.
+
+For this, we can write a validation just before the Library Transaction object is saved. To do this, open the `library_management/doctype/library_transaction/library_transaction.py` template.
+
+This file is the controller for the Library Transaction object. In this you can write methods for:
+
+1. `before_insert`
+1. `validate` (before inserting or updating)
+1. `on_update` (after saving)
+1. `on_submit` (when document is set as submitted)
+1. `on_cancel`
+1. `on_trash` (before it is about to be deleted)
+
+You can write methods for these events and they will be called by the framework when the document is saved etc.
+
+Here is the finished controller:
+
+ from __future__ import unicode_literals
+ import frappe
+ from frappe import _
+ from frappe.model.document import Document
+
+ class LibraryTransaction(Document):
+ def validate(self):
+ last_transaction = frappe.get_list("Library Transaction",
+ fields=["transaction_type", "transaction_date"],
+ filters = {
+ "article": self.article,
+ "transaction_date": ("<=", self.transaction_date),
+ "name": ("!=", self.name)
+ })
+ if self.transaction_type=="Issue":
+ msg = _("Article {0} {1} has not been recorded as returned since {2}")
+ if last_transaction and last_transaction[0].transaction_type=="Issue":
+ frappe.throw(msg.format(self.article, self.article_name,
+ last_transaction[0].transaction_date))
+ else:
+ if not last_transaction or last_transaction[0].transaction_type!="Issue":
+ frappe.throw(_("Cannot return article not issued"))
+
+In this script:
+
+1. We get the last trasaction before the current transaction date using the query function `frappe.get_list`
+1. If the last transaction is something we don't like we throw an exception using `frappe.throw`
+1. We use `_("text")` method to identify translatable strings.
+
+Check if your validations work by creating new records
+
+
+
+#### Debugging
+
+To Debug, always keep your JS Console open. Lookout for both Javascript and server tracebacks.
+
+Also check your terminal window for exceptions. Any **500 Internal Server Errors** will get printed in your terminal where on which your server is running.
+
+{next}
diff --git a/frappe/docs/user/tutorial/doctype-directory-structure.md b/frappe/docs/user/tutorial/doctype-directory-structure.md
new file mode 100644
index 0000000000..b5e1b10006
--- /dev/null
+++ b/frappe/docs/user/tutorial/doctype-directory-structure.md
@@ -0,0 +1,31 @@
+# DocType Directory Structure
+
+After saving the DocTypes, check that the model `.json` and `.py` files are created in the `apps/library_management/library_management` module. The directory structure after creating the models should look like this:
+
+ .
+ ├── MANIFEST.in
+ ├── README.md
+ ├── library_management
+ ..
+ │ ├── library_management
+ │ │ ├── __init__.py
+ │ │ └── doctype
+ │ │ ├── __init__.py
+ │ │ ├── article
+ │ │ │ ├── __init__.py
+ │ │ │ ├── article.json
+ │ │ │ └── article.py
+ │ │ ├── library_member
+ │ │ │ ├── __init__.py
+ │ │ │ ├── library_member.json
+ │ │ │ └── library_member.py
+ │ │ ├── library_membership
+ │ │ │ ├── __init__.py
+ │ │ │ ├── library_membership.json
+ │ │ │ └── library_membership.py
+ │ │ └── library_transaction
+ │ │ ├── __init__.py
+ │ │ ├── library_transaction.json
+ │ │ └── library_transaction.py
+
+{next}
diff --git a/frappe/docs/user/tutorial/doctypes.md b/frappe/docs/user/tutorial/doctypes.md
new file mode 100644
index 0000000000..c089cbbbc9
--- /dev/null
+++ b/frappe/docs/user/tutorial/doctypes.md
@@ -0,0 +1,96 @@
+# DocType
+
+After creating the Roles, let us create the **DocTypes**
+
+To create a new **DocType**, go to:
+
+> Developer > Documents > Doctype > New
+
+
+
+In the DocType, first the Module, which in our case is **Library Managment**
+
+#### Adding Fields
+
+In the Fields Table, you can add the fields (properties) of the DocType (Article).
+
+Fields are much more than database columns, they can be:
+
+1. Columns in the database
+1. For Layout (section / column breaks)
+1. Child tables (Table type field)
+1. HTML
+1. Actions (button)
+1. Attachments or Images
+
+Let us add the fields of the Article.
+
+
+
+When you add fields, you need to enter the **Type**. **Label** is optional for Section Break and Column Break. **Name** (`fieldname`) is the name of the database table column and also the property of the controller. This has to be *code friendly*, i.e. it has to have small cases are _ instead of " ". If you leave the Fieldname blank, it will be automatically set when you save it.
+
+You can also set other properties of the field like whether it is mandatory, read only etc.
+
+We can add the following fields:
+
+1. Article Name (Data)
+2. Author (Data)
+3. Description
+4. ISBN
+5. Status (Select): For Select fields, you will enter the Options. Enter **Issued** and **Available** each on a new line in the Options box. See diagram below
+6. Publisher (Data)
+7. Language (Data)
+8. Image (Attach Image)
+
+
+#### Add Permissions
+
+After adding the fields, hit done and add a new row in the Permission Rules section. For now, let us give Read, Write, Create, Delete and Report access to **Librarian**. Frappe has a finely grained Role based permission model. You can also change permissions later using the **Role Permissions Manager** from **Setup**.
+
+
+
+#### Saving
+
+Click on the **Save** button. When the button is clicked, a popup will ask you for the name. Give it the name **Article** and save the DocType.
+
+Now login into mysql and check the database table created:
+
+ $ bench mysql
+ Welcome to the MariaDB monitor. Commands end with ; or \g.
+ Your MariaDB connection id is 3931
+ Server version: 5.5.36-MariaDB-log Homebrew
+
+ Copyright (c) 2000, 2014, Oracle, Monty Program Ab and others.
+
+ Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
+
+ MariaDB [library]> DESC tabArticle;
+ +--------------+--------------+------+-----+---------+-------+
+ | Field | Type | Null | Key | Default | Extra |
+ +--------------+--------------+------+-----+---------+-------+
+ | name | varchar(255) | NO | PRI | NULL | |
+ | creation | datetime(6) | YES | | NULL | |
+ | modified | datetime(6) | YES | | NULL | |
+ | modified_by | varchar(40) | YES | | NULL | |
+ | owner | varchar(60) | YES | | NULL | |
+ | docstatus | int(1) | YES | | 0 | |
+ | parent | varchar(255) | YES | MUL | NULL | |
+ | parentfield | varchar(255) | YES | | NULL | |
+ | parenttype | varchar(255) | YES | | NULL | |
+ | idx | int(8) | YES | | NULL | |
+ | article_name | varchar(255) | YES | | NULL | |
+ | status | varchar(255) | YES | | NULL | |
+ | description | text | YES | | NULL | |
+ | image | varchar(255) | YES | | NULL | |
+ | publisher | varchar(255) | YES | | NULL | |
+ | isbn | varchar(255) | YES | | NULL | |
+ | language | varchar(255) | YES | | NULL | |
+ | author | varchar(255) | YES | | NULL | |
+ +--------------+--------------+------+-----+---------+-------+
+ 18 rows in set (0.00 sec)
+
+
+As you can see, along with the DocFields, several standard columns have also been added to the table. Important to note here are, the primary key, `name`, `owner`(the user who has created the record), `creation` and `modified` (timestamps for creation and last modification).
+
+{next}
+
diff --git a/frappe/docs/user/tutorial/form-client-scripting.md b/frappe/docs/user/tutorial/form-client-scripting.md
new file mode 100644
index 0000000000..a2afd1033c
--- /dev/null
+++ b/frappe/docs/user/tutorial/form-client-scripting.md
@@ -0,0 +1,37 @@
+## Scripting Forms
+
+Now we have created a basic system that works out of the box without us having to write any code. Let us now write some scripts to make the application richer and add validations so that the user does not enter wrong data.
+
+### Client Side Scripting
+
+In the **Library Transaction** DocType, we have only field for Member Name. We have not made two fields. Now this could well be two fields (and probably should), but for the sake of example, let us consider we have to implement this. To do this we would have to write a event handler for the event when the user selects the `library_member` field and then access the member resource from the server using REST API and set the values in the form.
+
+To start the script, in the `library_management/doctype/library_transaction` folder, create a new file `library_transaction.js`. This file will be automatically executed when the first Library Transaction is opened by the user. So in this file, we can bind events and write other functions.
+
+#### library_transaction.js
+
+ frappe.ui.form.on("Library Transaction", "library_member",
+ function(frm) {
+ frappe.call({
+ "method": "frappe.client.get",
+ args: {
+ doctype: "Library Member",
+ name: frm.doc.library_member
+ },
+ callback: function (data) {
+ frappe.model.set_value(frm.doctype,
+ frm.docname, "member_name",
+ data.message.first_name
+ + (data.message.last_name ?
+ (" " + data.message.last_name) : ""))
+ }
+ })
+ });
+
+1. **frappe.ui.form.on(*doctype*, *fieldname*, *handler*)** is used to bind a handler to the event when the property library_member is set.
+1. In the handler, we trigger an AJAX call to `frappe.client.get`. In response we get the requested object as JSON. [Learn more about the API](/help/rest_api).
+1. Using **frappe.model.set_value(*doctype*, *name*, *fieldname*, *value*)** we set the value in the form.
+
+**Note:** To check if your script works, remember to 'reload' the page before testing your script. Client script changes are not automatically picked up when you are in developer mode.
+
+{next}
diff --git a/frappe/docs/user/tutorial/index.md b/frappe/docs/user/tutorial/index.md
new file mode 100644
index 0000000000..13015b7b9e
--- /dev/null
+++ b/frappe/docs/user/tutorial/index.md
@@ -0,0 +1,33 @@
+# Frappe Tutorial
+
+In this guide we will show you how to create an application from scratch using **Frappe**. Using the example of a Library Management System, we will cover:
+
+1. Installation
+1. Making a New App
+1. Making Models
+1. Creating Users and Records
+1. Creating Controllers
+1. Creating Web Views
+1. Setting Hooks and Tasks
+
+## Who is This For?
+
+This guide is intended for software developers who are familiar with how the web applications are built and served. Frappe Framework is built on Python and uses MariaDB database and for creating web views, HTML/CSS/Javascript is used. So it would be great if you are familiar with all these techonlogies. At minimum if you have never used Python before, you should take a quick tutorial before your use this Guide.
+
+Frappe uses the git version control system on GitHub. It is also important that you are familiar with basic git and have an account on GitHub to manage your applications.
+
+## Example
+
+For this guide book, we will build a simple **Library Management** application. In this application we will have models:
+
+1. Article (Book or any other item that can be loaned)
+1. Library Member
+1. Library Transaction (Issue or Return of an article)
+1. Library Membership (A period in which a member is allowed to transact)
+1. Library Management Setting (Global settings like period of loan)
+
+The user interface (UI) for the librarian will be the **Frappe Desk**, a built-in browser based UI enviornment where forms are automatically generated from the models and roles and permissions are also applied.
+
+We will also create web views for library where users can browser articles from a website.
+
+{index}
diff --git a/frappe/docs/user/tutorial/index.txt b/frappe/docs/user/tutorial/index.txt
new file mode 100644
index 0000000000..1fed6aed93
--- /dev/null
+++ b/frappe/docs/user/tutorial/index.txt
@@ -0,0 +1,19 @@
+before
+app
+bench
+new-app
+setting-up-the-site
+start
+models
+roles
+doctypes
+naming-and-linking
+doctype-directory-structure
+users-and-records
+form-client-scripting
+controllers
+reports
+web-views
+single-doctypes
+task-runner
+conclusion
diff --git a/frappe/docs/user/tutorial/models.md b/frappe/docs/user/tutorial/models.md
new file mode 100644
index 0000000000..636c013b08
--- /dev/null
+++ b/frappe/docs/user/tutorial/models.md
@@ -0,0 +1,19 @@
+# Making Models
+
+The next step is to create the models as we discussed in the introduction. In Frappe, models are called **DocType**. You can create new DocTypes from the Desk UI. **DocTypes** are made of fields called **DocField** and role based permissions are integrated into the models, these are called **DocPerms**.
+
+When a DocType is saved, a new table is created in the database. This table is named as `tab[doctype]`.
+
+When you create a **DocType** a new folder is created in the **Module** and a model JSON file and a controller template in Python are automatically created. When you update the DocType, the JSON model file is updated and whenever `bench migrate` is executed, it is synced with the database. This makes it easy to propagate schema changes and migrate.
+
+### Developer Mode
+
+To create models, you must set `developer_mode` as 1 in the `site_config.json` file located in /sites/library and execute command `bench clear-cache` or use the user menu in UI and click on "Reload" for the changes to take effect. You should now see the "Developer" app on your desk
+
+ {
+ "db_name": "library",
+ "db_password": "v3qHDeVKvWVi7s97",
+ "developer_mode": 1
+ }
+
+{next}
diff --git a/frappe/docs/user/tutorial/naming-and-linking.md b/frappe/docs/user/tutorial/naming-and-linking.md
new file mode 100644
index 0000000000..f32c1d12be
--- /dev/null
+++ b/frappe/docs/user/tutorial/naming-and-linking.md
@@ -0,0 +1,71 @@
+# DocType Naming and Linking
+
+Then let us create the other DocType and save it too:
+
+1. Library Member (First Name, Last Name, Email ID, Phone, Address)
+
+
+
+
+#### Naming of DocTypes
+
+DocTypes can be named in different ways:
+
+1. Based on a field
+1. Based on a series
+1. By controller (code)
+1. Prompt
+
+This can be set by entering the **Autoname** field. For controller, leave blank.
+
+> **Search Fields**: A DocType may be named on a series but it still needs to be searched by name. In our case, the Article will be searched by the title or the author name. So this can be entered in search field.
+
+
+
+#### Link and Select Fields
+
+Foreign keys are specified in Frappe as **Link** type fields. The target DocType must be mentioned in the Options table.
+
+In our example, in the Library Transaction DocType, we have to link both the Library Member and the Article.
+
+**Note:** Remeber that Link fields are not automatically set as Foreign Keys in the MariaDB database, because that will implicitly index the column. This may not be optimum hence the Foreign Key validation is done by the Framework.
+
+
+
+For select fields, as we mentioned earlier, add the various options in the **Options** input box, each option on a new row.
+
+
+
+Similary complete making the other models.
+
+#### Linked Values
+
+A standard pattern is when you select an ID, say **Library Member** in **Library Membership**, then the Member's first and last names should be copied into relevant fields in the Library Membership Transaction.
+
+To do this, we can use Read Only fields and in options, we can set the the name of the link and the fieldname of the property we want to fetch. For this example in **Member First Name** we can set `library_member.first_name`
+
+
+
+### Complete the Models
+
+In the same way, you can complete all the models so that the final fields look like this:
+
+#### Article
+
+
+
+#### Library Member
+
+
+
+#### Library Membership
+
+
+
+#### Library Transaction
+
+
+
+> Make sure to give permissions to **Librarian** on each DocType
+
+{next}
diff --git a/frappe/docs/user/tutorial/new-app.md b/frappe/docs/user/tutorial/new-app.md
new file mode 100644
index 0000000000..63f4b63a08
--- /dev/null
+++ b/frappe/docs/user/tutorial/new-app.md
@@ -0,0 +1,54 @@
+# Make a New App
+
+After the bench is installed, there are two main folders, `apps` and `sites`. All the applications will be installed in apps.
+
+To make a new application, go to your bench folder and run, `bench new-app {app_name}` and fill in details about the application. This will create a boilerplate application for your.
+
+ $ bench new-app library_management
+ App Title (defaut: Lib Mgt): Liblary Management
+ App Description: App for managing Articles, Members, Memberships and Transactions for Libraries
+ App Publisher: Frappe
+ App Email: info@frappe.io
+ App Icon (default 'octicon octicon-file-directory'): octicon octicon-book
+ App Color (default 'grey'): #589494
+ App License (default 'MIT'): GNU General Public License
+
+### App Structure
+
+The application will be created in a folder called `library_management` and will have the following structure:
+
+ .
+ ├── MANIFEST.in
+ ├── README.md
+ ├── library_management
+ │ ├── __init__.py
+ │ ├── config
+ │ │ ├── __init__.py
+ │ │ └── desktop.py
+ │ ├── hooks.py
+ │ ├── library_management
+ │ │ └── __init__.py
+ │ ├── modules.txt
+ │ ├── patches.txt
+ │ └── templates
+ │ ├── __init__.py
+ │ ├── generators
+ │ │ └── __init__.py
+ │ ├── pages
+ │ │ └── __init__.py
+ │ └── statics
+ ├── license.txt
+ ├── requirements.txt
+ └── setup.py
+
+1. `config` folder contains application configuration info
+1. `desktop.py` is where desktop icons can be added to the Desk
+1. `hooks.py` is where integrations with the environment and other applications is mentioned.
+1. `library_management` (inner) is a **module** that is bootstrapped. In Frappe, a **module** is where model and controller files reside.
+1. `modules.txt` contains list of **modules** in the app. When you create a new module, it is required that you update it in this file.
+1. `patches.txt` is where migration patches are written. They are python module references using the dot notation.
+1. `templates` is the folder where web view templates are maintained. Templates for **Login** and other standard pages are bootstrapped in frappe.
+1. `generators` are where templates for models are maintained, where each model instance has a separte web route, for example a **Blog Post** where each post has its unique web url. In Frappe, the templating engine used is Jinja2
+1. `pages` is where single route templates are maintained. For example for a "/blog" type of page.
+
+{next}
diff --git a/frappe/docs/user/tutorial/reports.md b/frappe/docs/user/tutorial/reports.md
new file mode 100644
index 0000000000..1b2d23262f
--- /dev/null
+++ b/frappe/docs/user/tutorial/reports.md
@@ -0,0 +1,7 @@
+# Reports
+
+You can also click on the Reports Icon on the toolbar (right) to see tabulated records
+
+
+
+{next}
diff --git a/frappe/docs/user/tutorial/roles.md b/frappe/docs/user/tutorial/roles.md
new file mode 100644
index 0000000000..d358556083
--- /dev/null
+++ b/frappe/docs/user/tutorial/roles.md
@@ -0,0 +1,14 @@
+# Creating Roles
+
+Before creating Models, we must create Roles so that we can set permissions on the Model. There are two Roles we will create:
+
+1. Librarian
+1. Library Member
+
+To create a new Role, go to:
+
+> Setup > Users > Role > New
+
+
+
+{next}
diff --git a/frappe/docs/user/tutorial/setting-up-the-site.md b/frappe/docs/user/tutorial/setting-up-the-site.md
new file mode 100644
index 0000000000..7a122a639a
--- /dev/null
+++ b/frappe/docs/user/tutorial/setting-up-the-site.md
@@ -0,0 +1,53 @@
+# Setting up the Site
+
+Let us create a new site and call it `library`.
+
+You can install a new site, by the command `bench new-site library`
+
+This will create a new database and site folder and install `frappe` (which is also an application!) in the new site. The `frappe` application has two built-in modules **Core** and **Website**. The Core module contains the basic models for the application. Frappe is a batteries included framework and comes with a lot of built-in models. These models are called **DocTypes**. More on that later.
+
+ $ bench new-site library
+ MySQL root password:
+ Installing frappe...
+ Updating frappe : [========================================]
+ Updating country info : [========================================]
+ Set Administrator password:
+ Re-enter Administrator password:
+ Installing fixtures...
+ *** Scheduler is disabled ***
+
+### Site Structure
+
+A new folder called `library` will be created in the `sites` folder. Here is the standard folder structure for a site.
+
+ .
+ ├── locks
+ ├── private
+ │ └── backups
+ ├── public
+ │ └── files
+ └── site_config.json
+
+1. `public/files` is where user uploaded files are stored.
+1. `private/backups` is where backups are dumped
+1. `site_config.json` is where site level configurations are maintained.
+
+### Setting Default Site
+
+In case you have multiple sites on you bench use `bench use [site_name]` to set the default site.
+
+Example:
+
+ $ bench use library
+
+### Install App
+
+Now let us install our app `library_management` in our site `library`
+
+1. Install library_management in library with: `bench --site [site_name] install-app [app_name]`
+
+Example:
+
+ $ bench install-app library_management
+
+{next}
diff --git a/frappe/docs/user/tutorial/single-doctypes.md b/frappe/docs/user/tutorial/single-doctypes.md
new file mode 100644
index 0000000000..9b0e4171b1
--- /dev/null
+++ b/frappe/docs/user/tutorial/single-doctypes.md
@@ -0,0 +1,9 @@
+# Single DocTypes
+
+A application will usually have a Settings page. In our application, we can define a page where we can set the loan period. We also need to save this property. In Frappe, this can be done using a **Single** type DocType. A Single DocType is like the Singleton pattern in Java. It is an object with only one instance. Let us call this as **Library Managment Settings**.
+
+To create an new Single DocType, mark the **Is Single** property as checked.
+
+
+
+{next}
diff --git a/frappe/docs/user/tutorial/start.md b/frappe/docs/user/tutorial/start.md
new file mode 100644
index 0000000000..2a2000850e
--- /dev/null
+++ b/frappe/docs/user/tutorial/start.md
@@ -0,0 +1,31 @@
+# Starting the Bench
+
+Now we can login and check if everything works.
+
+To start the development server, run `bench start`
+
+ $ bench start
+ 13:58:51 web.1 | started with pid 22135
+ 13:58:51 worker.1 | started with pid 22136
+ 13:58:51 workerbeat.1 | started with pid 22137
+ 13:58:52 web.1 | * Running on http://0.0.0.0:8000/
+ 13:58:52 web.1 | * Restarting with reloader
+ 13:58:52 workerbeat.1 | [2014-09-17 13:58:52,343: INFO/MainProcess] beat: Starting...
+
+You can now open your browser and go to `http://localhost:8000`. You should see this login page if all goes well:
+
+
+
+Now login with :
+
+Login ID: **Administrator**
+
+Password : **Use the password that was generated during installation**
+
+When you login, you should see the "Desk" home page
+
+
+
+As you can see, the Frappe basic system comes with a bunch of pre-loaded applications and screens like To Do, Calendar etc. These apps can integrated in your app workflow as we progress.
+
+{next}
diff --git a/frappe/docs/user/tutorial/task-runner.md b/frappe/docs/user/tutorial/task-runner.md
new file mode 100644
index 0000000000..cb704c12bd
--- /dev/null
+++ b/frappe/docs/user/tutorial/task-runner.md
@@ -0,0 +1,77 @@
+# Scheduled Tasks
+
+Finally, an application also has to send email notifications and do other kind of scheduled tasks. In Frappe, if you have setup the bench, the task / scheduler is setup via Celery using Redis Queue.
+
+To add a new task handler, go to `hooks.py` and add a new handler. Default handlers are `all`, `daily`, `weekly`, `monthly`. The `all` handler is called every 3 minutes by default.
+
+ # Scheduled Tasks
+ # ---------------
+
+ scheduler_events = {
+ "daily": [
+ "library_management.tasks.daily"
+ ],
+ }
+
+Here we can point to a Python function and that function will be executed every day. Let us look what this function looks like:
+
+ # Copyright (c) 2013, Frappe
+ # For license information, please see license.txt
+
+ from __future__ import unicode_literals
+ import frappe
+ from frappe.utils import datediff, nowdate, format_date, add_days
+
+ def daily():
+ loan_period = frappe.db.get_value("Library Management Settings",
+ None, "loan_period")
+
+ overdue = get_overdue(loan_period)
+
+ for member, items in overdue.iteritems():
+ content = """Following Items are Overdue
+ Please return them as soon as possible
"""
+
+ for i in items:
+ content += "{0} ({1}) due on {2} ".format(i.article_name,
+ i.article,
+ format_date(add_days(i.transaction_date, loan_period)))
+
+ content += " "
+
+ recipient = frappe.db.get_value("Library Member", member, "email_id")
+ frappe.sendmail(recipients=[recipient],
+ sender="test@example.com",
+ subject="Library Articles Overdue", content=content, bulk=True)
+
+ def get_overdue(loan_period):
+ # check for overdue articles
+ today = nowdate()
+
+ overdue_by_member = {}
+ articles_transacted = []
+
+ for d in frappe.db.sql("""select name, article, article_name,
+ library_member, member_name
+ from `tabLibrary Transaction`
+ order by transaction_date desc, modified desc""", as_dict=1):
+
+ if d.article in articles_transacted:
+ continue
+
+ if d.transaction_type=="Issue" and \
+ datediff(today, d.transaction_date) > loan_period:
+ overdue_by_member.setdefault(d.library_member, [])
+ overdue_by_member[d.library_member].append(d)
+
+ articles_transacted.append(d.article)
+
+We can place the above code code in any accessible Python module. The route is defined in `hooks.py`, so for our purposes we would place this code in `library_management/tasks.py`.
+
+Note:
+
+1. We get the loan period from **Library Management Settings** by using `frappe.db.get_value`.
+1. We run a query in the database with `frappe.db.sql`
+1. Email is sent via `frappe.sendmail`
+
+{next}
diff --git a/frappe/docs/user/tutorial/users-and-records.md b/frappe/docs/user/tutorial/users-and-records.md
new file mode 100644
index 0000000000..61e6b6dec1
--- /dev/null
+++ b/frappe/docs/user/tutorial/users-and-records.md
@@ -0,0 +1,55 @@
+# Making Users and Records
+
+Now that we have created the models, we can directly start making records using Frappe Desk UI. You do not have to create views! Views in Frappe are automatically made based on the DocType properties.
+
+### 4.1 Creating User
+
+To make records, we will first create a User. To create a user, go to:
+
+> Setup > Users > User > New
+
+Create a new User and set the name and first name and new password.
+
+Also give the Librarian and Library Member Roles to this user
+
+
+
+Now logout and login using the new user id and password.
+
+### 4.2 Creating Records
+
+You will now see an icon for the Library Management module. Click on that icon and you will see the Module page:
+
+
+
+Here you can see the DocTypes that we have created for the application. Let us start creating a few records.
+
+First let us create a new Article:
+
+
+
+Here you will see that the the DocType you had created has been rendered as a form. The validations and other rules will also apply as designed. Let us fill out one Article.
+
+
+
+You can also add an image.
+
+
+
+Now let us create a new member:
+
+
+
+After this, let us create a new membership record for the member.
+
+Here if you remember we had set the values of Member First Name and Member Last Name to be directly fetched from the Member records and as soon as you will select the member id, the names will be updated.
+
+
+
+As you can see that the date is formatted as year-month-day which is a system format. To set / change date, time and number formats, go to
+
+> Setup > Settings > System Settings
+
+
+
+{next}
diff --git a/frappe/docs/user/tutorial/web-views.md b/frappe/docs/user/tutorial/web-views.md
new file mode 100644
index 0000000000..a1dd2af2c6
--- /dev/null
+++ b/frappe/docs/user/tutorial/web-views.md
@@ -0,0 +1,64 @@
+# Web Views
+
+Frappe has two main user environments, the Desk and Web. Desk is a controlled UI environment with a rich AJAX application and the web is more traditional HTML templates served for public consumption. Web views can also be generated to create more controlled views for users who may login but still do not have access to the Desk.
+
+In Frappe, Web Views are managed by templates and they are usually in the `templates` folder. There are 2 main types of templates.
+
+1. Pages: These are Jinja templates where a single view exists for a single web route e.g. `/blog`.
+2. Generators: These are templates where each instance of a DocType has a separate web route `/blog/a-blog`, `blog/b-blog` etc.
+3. Lists and Views: These are standard lists and views with the route `[doctype]/[name]` and are rendered based on permission.
+
+### Standard Web Views
+
+> This features is still under development.
+
+Let us look at the standard Web Views:
+
+If you are logged in as the test user, go to `/article` and you should see the list of articles:
+
+
+
+Click on one article and you will see the default web view
+
+
+
+Now if you want to make a better list view for the article, drop a file called `list_item.html` in the `library_management/doctype/article` folder. Here is an example file:
+
+
+
+
+
{{ doc.article_name }}
+
{{ doc.author }}
+
{{ (doc.description[:200] + "...")
+ if doc.description|length > 200 else doc.description }}
+
Publisher: {{ doc.publisher }}
+
+
+
+
+Here, you will get all the properties of the article in the `doc` object.
+
+The updated list view looks like this!
+
+
+
+#### Home Page
+
+Frappe also has a built-in signup workflow which also includes 3rd party signups via Google, Facebook and GitHub. When a user signs up on the web, she does not have access to the desk interface by default.
+
+> To allow user access into the Desk, open set the user from Setup > User and set the User Type as "System User"
+
+Now for the non system users, we can set a home page when they login via `hooks.py` based on the role.
+
+To when library members sign in, they must be redirected to the `article` page, to set this open `library_management/hooks.py` and add this:
+
+ role_home_page = {
+ "Library Member": "article"
+ }
+
+{next}
diff --git a/frappe/docs/user/videos/index.md b/frappe/docs/user/videos/index.md
new file mode 100644
index 0000000000..edcdf8ac54
--- /dev/null
+++ b/frappe/docs/user/videos/index.md
@@ -0,0 +1,9 @@
+# Video Tutorials for Frappe Framework
+
+This 10-part video tutorial will teach you how to build complex apps in Frappe
+
+Pre-requisites: You must have some understanding of Python, Javascript and MySQL before you start this tutorial.
+
+---
+
+VIDEO
diff --git a/frappe/email/__init__.py b/frappe/email/__init__.py
index c0bb639b87..4218598484 100644
--- a/frappe/email/__init__.py
+++ b/frappe/email/__init__.py
@@ -28,11 +28,11 @@ def sendmail_to_system_managers(subject, content):
@frappe.whitelist()
def get_contact_list():
"""Returns contacts (from autosuggest)"""
- cond = ['`%s` like "%s%%"' % (f,
- frappe.form_dict.get('txt')) for f in frappe.form_dict.get('where').split(',')]
+ cond = ['`%s` like "%s%%"' % (frappe.db.escape(f),
+ frappe.db.escape(frappe.form_dict.get('txt'))) for f in frappe.form_dict.get('where').split(',')]
cl = frappe.db.sql("select `%s` from `tab%s` where %s" % (
- frappe.form_dict.get('select')
- ,frappe.form_dict.get('from')
+ frappe.db.escape(frappe.form_dict.get('select'))
+ ,frappe.db.escape(frappe.form_dict.get('from'))
,' OR '.join(cond)
)
)
diff --git a/frappe/email/bulk.py b/frappe/email/bulk.py
index 280e2d6d60..b18d888d9e 100644
--- a/frappe/email/bulk.py
+++ b/frappe/email/bulk.py
@@ -4,18 +4,20 @@
from __future__ import unicode_literals
import frappe
import HTMLParser
+import smtplib
from frappe import msgprint, throw, _
from frappe.email.smtp import SMTPServer, get_outgoing_email_account
from frappe.email.email_body import get_email, get_formatted_html
from frappe.utils.verified_command import get_signed_params, verify_request
from html2text import html2text
-from frappe.utils import get_url, nowdate, encode, now_datetime, add_days
+from frappe.utils import get_url, nowdate, encode, now_datetime, add_days, split_emails
class BulkLimitCrossedError(frappe.ValidationError): pass
def send(recipients=None, sender=None, subject=None, message=None, reference_doctype=None,
reference_name=None, unsubscribe_method=None, unsubscribe_params=None, unsubscribe_message=None,
- attachments=None, reply_to=None, cc=(), message_id=None, send_after=None):
+ attachments=None, reply_to=None, cc=(), show_as_cc=(), message_id=None, send_after=None,
+ expose_recipients=False, bulk_priority=1):
"""Add email to sending queue (Bulk Email)
:param recipients: List of recipients.
@@ -24,6 +26,7 @@ def send(recipients=None, sender=None, subject=None, message=None, reference_doc
:param message: Email message.
:param reference_doctype: Reference DocType of caller document.
:param reference_name: Reference name of caller document.
+ :param bulk_priority: Priority for bulk email, default 1.
:param unsubscribe_method: URL method for unsubscribe. Default is `/api/method/frappe.email.bulk.unsubscribe`.
:param unsubscribe_params: additional params for unsubscribed links. default are name, doctype, email
:param attachments: Attachments to be sent.
@@ -38,14 +41,14 @@ def send(recipients=None, sender=None, subject=None, message=None, reference_doc
return
if isinstance(recipients, basestring):
- recipients = recipients.split(",")
+ recipients = split_emails(recipients)
if isinstance(send_after, int):
send_after = add_days(nowdate(), send_after)
if not sender or sender == "Administrator":
email_account = get_outgoing_email_account()
- sender = email_account.get("sender") or email_account.email_id
+ sender = email_account.default_sender
check_bulk_limit(recipients)
@@ -59,34 +62,54 @@ def send(recipients=None, sender=None, subject=None, message=None, reference_doc
if reference_doctype and reference_name:
unsubscribed = [d.email for d in frappe.db.get_all("Email Unsubscribe", "email",
{"reference_doctype": reference_doctype, "reference_name": reference_name})]
+
+ unsubscribed += [d.email for d in frappe.db.get_all("Email Unsubscribe", "email",
+ {"global_unsubscribe": 1})]
else:
unsubscribed = []
- for email in filter(None, list(set(recipients))):
- if email not in unsubscribed:
- email_content = formatted
- email_text_context = text_content
+ recipients = [r for r in list(set(recipients)) if r and r not in unsubscribed]
- if reference_doctype:
- unsubscribe_url = get_unsubcribed_url(reference_doctype, reference_name, email,
- unsubscribe_method, unsubscribe_params)
+ for email in recipients:
+ email_content = formatted
+ email_text_context = text_content
- # add to queue
- email_content = add_unsubscribe_link(email_content, email, reference_doctype,
- reference_name, unsubscribe_url, unsubscribe_message)
+ if reference_doctype:
+ unsubscribe_link = get_unsubscribe_link(
+ reference_doctype=reference_doctype,
+ reference_name=reference_name,
+ email=email,
+ recipients=recipients,
+ expose_recipients=expose_recipients,
+ unsubscribe_method=unsubscribe_method,
+ unsubscribe_params=unsubscribe_params,
+ unsubscribe_message=unsubscribe_message,
+ show_as_cc=show_as_cc
+ )
- email_text_context += "\n" + _("This email was sent to {0}. To unsubscribe click on this link: {1}").format(email, unsubscribe_url)
+ email_content = email_content.replace("", unsubscribe_link.html)
+ email_text_context += unsubscribe_link.text
- add(email, sender, subject, email_content, email_text_context, reference_doctype,
- reference_name, attachments, reply_to, cc, message_id, send_after)
+ # show as cc
+ cc_message = ""
+ if email in show_as_cc:
+ cc_message = _("This email was sent to you as CC")
+
+ email_content = email_content.replace("", cc_message)
+ email_text_context = cc_message + "\n" + email_text_context
+
+ # add to queue
+ add(email, sender, subject, email_content, email_text_context, reference_doctype,
+ reference_name, attachments, reply_to, cc, message_id, send_after, bulk_priority)
def add(email, sender, subject, formatted, text_content=None,
reference_doctype=None, reference_name=None, attachments=None, reply_to=None,
- cc=(), message_id=None, send_after=None):
+ cc=(), message_id=None, send_after=None, bulk_priority=1):
"""add to bulk mail queue"""
e = frappe.new_doc('Bulk Email')
e.sender = sender
e.recipient = email
+ e.priority = bulk_priority
try:
mail = get_email(email, sender=e.sender, formatted=formatted, subject=subject,
@@ -107,32 +130,66 @@ def add(email, sender, subject, formatted, text_content=None,
e.insert(ignore_permissions=True)
def check_bulk_limit(recipients):
+ # get count of mails sent this month
this_month = frappe.db.sql("""select count(*) from `tabBulk Email` where
- MONTH(creation)=MONTH(CURDATE())""")[0][0]
+ status='Sent' and MONTH(creation)=MONTH(CURDATE())""")[0][0]
+ # if using settings from site_config.json, check bulk limit
# No limit for own email settings
smtp_server = SMTPServer()
- if smtp_server.email_account and getattr(smtp_server.email_account,
- "from_site_config", False) or frappe.flags.in_test:
+ if (smtp_server.email_account
+ and getattr(smtp_server.email_account, "from_site_config", False)
+ or frappe.flags.in_test):
+
monthly_bulk_mail_limit = frappe.conf.get('monthly_bulk_mail_limit') or 500
if (this_month + len(recipients)) > monthly_bulk_mail_limit:
- throw(_("Email limit {0} crossed").format(monthly_bulk_mail_limit),
+ throw(_("Cannot send this email. You have crossed the sending limit of {0} emails for this month.").format(monthly_bulk_mail_limit),
BulkLimitCrossedError)
-def add_unsubscribe_link(message, email, reference_doctype, reference_name, unsubscribe_url, unsubscribe_message):
- unsubscribe_link = """""".format(unsubscribe_url = unsubscribe_url,
- email= _("This email was sent to {0}").format(email),
- unsubscribe_message = unsubscribe_message or _("Unsubscribe from this list"))
+def get_unsubscribe_link(reference_doctype, reference_name,
+ email, recipients, expose_recipients, show_as_cc,
+ unsubscribe_method, unsubscribe_params, unsubscribe_message):
- message = message.replace("", unsubscribe_link)
+ email_sent_to = recipients if expose_recipients else [email]
+ email_sent_cc = ", ".join([e for e in email_sent_to if e in show_as_cc])
+ email_sent_to = ", ".join([e for e in email_sent_to if e not in show_as_cc])
- return message
+ if email_sent_cc:
+ email_sent_message = _("This email was sent to {0} and copied to {1}").format(email_sent_to, email_sent_cc)
+ else:
+ email_sent_message = _("This email was sent to {0}").format(email_sent_to)
+
+ if not unsubscribe_message:
+ unsubscribe_message = _("Unsubscribe from this list")
+
+ unsubscribe_url = get_unsubcribed_url(reference_doctype, reference_name, email,
+ unsubscribe_method, unsubscribe_params)
+
+ html = """""".format(
+ unsubscribe_url = unsubscribe_url,
+ email=email_sent_message,
+ unsubscribe_message=unsubscribe_message
+ )
+
+ text = "\n{email}\n\n{unsubscribe_message}: {unsubscribe_url}".format(
+ email=email_sent_message,
+ unsubscribe_message=unsubscribe_message,
+ unsubscribe_url=unsubscribe_url
+ )
+
+ return frappe._dict({
+ "html": html,
+ "text": text
+ })
def get_unsubcribed_url(reference_doctype, reference_name, email, unsubscribe_method, unsubscribe_params):
params = {"email": email.encode("utf-8"),
@@ -154,14 +211,19 @@ def unsubscribe(doctype, name, email):
if not verify_request():
return
- frappe.get_doc({
- "doctype": "Email Unsubscribe",
- "email": email,
- "reference_doctype": doctype,
- "reference_name": name
- }).insert(ignore_permissions=True)
+ try:
+ frappe.get_doc({
+ "doctype": "Email Unsubscribe",
+ "email": email,
+ "reference_doctype": doctype,
+ "reference_name": name
+ }).insert(ignore_permissions=True)
- frappe.db.commit()
+ except frappe.DuplicateEntryError:
+ frappe.db.rollback()
+
+ else:
+ frappe.db.commit()
return_unsubscribed_page(email, doctype, name)
@@ -174,17 +236,20 @@ def flush(from_test=False):
auto_commit = not from_test
- if frappe.flags.mute_emails or frappe.conf.get("mute_emails") or False:
+ # additional check
+ check_bulk_limit([])
+
+ if frappe.are_emails_muted():
msgprint(_("Emails are muted"))
from_test = True
frappe.db.sql("""update `tabBulk Email` set status='Expired'
- where datediff(curdate(), creation) > 3""", auto_commit=auto_commit)
+ where datediff(curdate(), creation) > 3 and status='Not Sent'""", auto_commit=auto_commit)
for i in xrange(500):
email = frappe.db.sql("""select * from `tabBulk Email` where
status='Not Sent' and ifnull(send_after, "2000-01-01 00:00:00") < %s
- order by creation asc limit 1 for update""", now_datetime(), as_dict=1)
+ order by priority desc, creation asc limit 1 for update""", now_datetime(), as_dict=1)
if email:
email = email[0]
else:
@@ -200,11 +265,27 @@ def flush(from_test=False):
frappe.db.sql("""update `tabBulk Email` set status='Sent' where name=%s""",
(email["name"],), auto_commit=auto_commit)
+ except (smtplib.SMTPServerDisconnected,
+ smtplib.SMTPConnectError,
+ smtplib.SMTPHeloError,
+ smtplib.SMTPAuthenticationError):
+
+ # bad connection, retry later
+ frappe.db.sql("""update `tabBulk Email` set status='Not Sent' where name=%s""",
+ (email["name"],), auto_commit=auto_commit)
+
+ # no need to attempt further
+ return
+
except Exception, e:
frappe.db.sql("""update `tabBulk Email` set status='Error', error=%s
where name=%s""", (unicode(e), email["name"]), auto_commit=auto_commit)
+ # NOTE: removing commit here because we pass auto_commit
+ # finally:
+ # frappe.db.commit()
+
def clear_outbox():
- """remove mails older than 30 days in Outbox"""
+ """Remove mails older than 31 days in Outbox. Called daily via scheduler."""
frappe.db.sql("""delete from `tabBulk Email` where
- datediff(now(), creation) > 30""")
+ datediff(now(), creation) > 31""")
diff --git a/frappe/email/doctype/bulk_email/bulk_email.json b/frappe/email/doctype/bulk_email/bulk_email.json
index e4807eba64..b84f496968 100644
--- a/frappe/email/doctype/bulk_email/bulk_email.json
+++ b/frappe/email/doctype/bulk_email/bulk_email.json
@@ -1,93 +1,257 @@
{
- "autoname": "hash",
- "creation": "2012-08-02 15:17:28",
- "description": "Bulk Email records.",
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "System",
+ "allow_copy": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "autoname": "hash",
+ "creation": "2012-08-02 15:17:28",
+ "custom": 0,
+ "description": "Bulk Email records.",
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "System",
"fields": [
{
- "fieldname": "sender",
- "fieldtype": "Data",
- "in_list_view": 0,
- "label": "Sender",
- "permlevel": 0
- },
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "fieldname": "sender",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Sender",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
{
- "fieldname": "recipient",
- "fieldtype": "Data",
- "in_list_view": 1,
- "label": "Recipient",
- "permlevel": 0
- },
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "fieldname": "recipient",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 1,
+ "label": "Recipient",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
{
- "fieldname": "message",
- "fieldtype": "Code",
- "in_list_view": 0,
- "label": "Message",
- "permlevel": 0
- },
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "fieldname": "message",
+ "fieldtype": "Code",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Message",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
{
- "default": "Not Sent",
- "fieldname": "status",
- "fieldtype": "Select",
- "in_list_view": 1,
- "label": "Status",
- "options": "\nNot Sent\nSending\nSent\nError",
- "permlevel": 0
- },
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "default": "Not Sent",
+ "fieldname": "status",
+ "fieldtype": "Select",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 1,
+ "label": "Status",
+ "length": 0,
+ "no_copy": 0,
+ "options": "\nNot Sent\nSending\nSent\nError\nExpired",
+ "permlevel": 0,
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
{
- "fieldname": "error",
- "fieldtype": "Text",
- "in_list_view": 0,
- "label": "Error",
- "permlevel": 0
- },
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "fieldname": "error",
+ "fieldtype": "Text",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Error",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
{
- "fieldname": "reference_doctype",
- "fieldtype": "Link",
- "label": "Reference DocType",
- "options": "DocType",
- "permlevel": 0,
- "read_only": 1,
- "reqd": 0
- },
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "fieldname": "reference_doctype",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Reference DocType",
+ "length": 0,
+ "no_copy": 0,
+ "options": "DocType",
+ "permlevel": 0,
+ "print_hide": 0,
+ "read_only": 1,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
{
- "fieldname": "reference_name",
- "fieldtype": "Data",
- "label": "Reference DocName",
- "permlevel": 0,
- "read_only": 1,
- "reqd": 0
- },
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "fieldname": "reference_name",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Reference DocName",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "print_hide": 0,
+ "read_only": 1,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
{
- "fieldname": "send_after",
- "fieldtype": "Datetime",
- "label": "Send After",
- "no_copy": 1,
- "permlevel": 0,
- "precision": "",
- "read_only": 1
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "fieldname": "send_after",
+ "fieldtype": "Datetime",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Send After",
+ "length": 0,
+ "no_copy": 1,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "read_only": 1,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "default": "1",
+ "fieldname": "priority",
+ "fieldtype": "Int",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Priority",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "read_only": 1,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
}
- ],
- "icon": "icon-envelope",
- "idx": 1,
- "in_create": 1,
- "modified": "2015-05-21 07:26:13.627637",
- "modified_by": "Administrator",
- "module": "Email",
- "name": "Bulk Email",
- "owner": "Administrator",
+ ],
+ "hide_heading": 0,
+ "hide_toolbar": 0,
+ "icon": "icon-envelope",
+ "idx": 1,
+ "in_create": 1,
+ "in_dialog": 0,
+ "is_submittable": 0,
+ "issingle": 0,
+ "istable": 0,
+ "max_attachments": 0,
+ "modified": "2015-12-24 06:29:43.089602",
+ "modified_by": "Administrator",
+ "module": "Email",
+ "name": "Bulk Email",
+ "owner": "Administrator",
"permissions": [
{
- "delete": 1,
- "email": 1,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "System Manager"
+ "amend": 0,
+ "apply_user_permissions": 0,
+ "cancel": 0,
+ "create": 0,
+ "delete": 1,
+ "email": 1,
+ "export": 0,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "set_user_permissions": 0,
+ "share": 0,
+ "submit": 0,
+ "write": 0
}
- ],
- "read_only": 0
-}
\ No newline at end of file
+ ],
+ "read_only": 0,
+ "read_only_onload": 0
+}
diff --git a/frappe/email/doctype/email_account/email_account.js b/frappe/email/doctype/email_account/email_account.js
index ad369befe1..d706a85e0e 100644
--- a/frappe/email/doctype/email_account/email_account.js
+++ b/frappe/email/doctype/email_account/email_account.js
@@ -1,6 +1,6 @@
email_defaults = {
"GMail": {
- "pop3_server": "pop.gmail.com",
+ "email_server": "pop.gmail.com",
"use_ssl": 1,
"enable_outgoing": 1,
"smtp_server": "smtp.gmail.com",
@@ -8,7 +8,7 @@ email_defaults = {
"use_tls": 1
},
"Outlook.com": {
- "pop3_server": "pop3.live.com",
+ "email_server": "pop3.live.com",
"use_ssl": 1,
"enable_outgoing": 1,
"smtp_server": "smtp.live.com",
@@ -16,13 +16,37 @@ email_defaults = {
"use_tls": 1
},
"Yahoo Mail": {
- "pop3_server": "pop.mail.yahoo.com ",
+ "email_server": "pop.mail.yahoo.com",
"use_ssl": 1,
"enable_outgoing": 1,
"smtp_server": "smtp.mail.yahoo.com",
"smtp_port": 465,
"use_tls": 1
},
+ "Yandex.Mail": {
+ "email_server": "pop.yandex.com",
+ "use_ssl": 1,
+ "enable_outgoing": 1,
+ "smtp_server": "smtp.yandex.com",
+ "smtp_port": 465,
+ "use_tls": 0
+ },
+};
+
+email_defaults_imap = {
+ "GMail": {
+ "email_server": "imap.gmail.com"
+ },
+ "Outlook.com": {
+ "email_server": "imap.live.com"
+ },
+ "Yahoo Mail": {
+ "email_server": "imap.mail.yahoo.com"
+ },
+ "Yandex.Mail": {
+ "email_server": "imap.yandex.com"
+ },
+
};
frappe.ui.form.on("Email Account", {
@@ -30,6 +54,24 @@ frappe.ui.form.on("Email Account", {
$.each(email_defaults[frm.doc.service], function(key, value) {
frm.set_value(key, value);
})
+ if (frm.doc.use_imap) {
+ $.each(email_defaults_imap[frm.doc.service], function(key, value) {
+ frm.set_value(key, value);
+ });
+ }
+ frm.events.show_gmail_message_for_less_secure_apps(frm);
+ },
+ use_imap: function(frm) {
+ if (frm.doc.use_imap) {
+ $.each(email_defaults_imap[frm.doc.service], function(key, value) {
+ frm.set_value(key, value);
+ });
+ }
+ else{
+ $.each(email_defaults[frm.doc.service], function(key, value) {
+ frm.set_value(key, value);
+ });
+ }
},
email_id: function(frm) {
if(!frm.doc.email_account_name) {
@@ -41,12 +83,24 @@ frappe.ui.form.on("Email Account", {
enable_incoming: function(frm) {
frm.set_df_property("append_to", "reqd", frm.doc.enable_incoming);
},
+ notify_if_unreplied: function(frm) {
+ frm.set_df_property("send_notification_to", "reqd", frm.doc.notify_if_unreplied);
+ },
onload: function(frm) {
frm.set_df_property("append_to", "only_select", true);
frm.set_query("append_to", "frappe.email.doctype.email_account.email_account.get_append_to");
},
refresh: function(frm) {
- frm.set_df_property("append_to", "reqd", frm.doc.enable_incoming);
- }
+ frm.events.enable_incoming(frm);
+ frm.events.notify_if_unreplied(frm);
+ frm.events.show_gmail_message_for_less_secure_apps(frm);
+ },
+ show_gmail_message_for_less_secure_apps: function(frm) {
+ frm.dashboard.reset();
+ if(frm.doc.service==="GMail") {
+ frm.dashboard.set_headline_alert('GMail will only work if you allows access for Less Secure \
+ Apps in GMail Settings. Read this for details ');
+ }
+ },
});
-
diff --git a/frappe/email/doctype/email_account/email_account.json b/frappe/email/doctype/email_account/email_account.json
index a6879b2af3..e2a0ef04e3 100644
--- a/frappe/email/doctype/email_account/email_account.json
+++ b/frappe/email/doctype/email_account/email_account.json
@@ -7,25 +7,61 @@
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
- "document_type": "Master",
+ "document_type": "Setup",
"fields": [
{
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"fieldname": "email_settings",
"fieldtype": "Section Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
"label": "",
+ "length": 0,
+ "no_copy": 0,
"permlevel": 0,
- "precision": ""
- },
- {
- "fieldname": "service",
- "fieldtype": "Select",
- "label": "Service",
- "options": "\nGMail\nYahoo Mail\nOutlook.com",
- "permlevel": 0,
- "precision": ""
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
},
{
"allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "fieldname": "service",
+ "fieldtype": "Select",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Service",
+ "length": 0,
+ "no_copy": 0,
+ "options": "\nGMail\nYahoo Mail\nOutlook.com\nYandex.Mail",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"fieldname": "email_id",
"fieldtype": "Data",
"hidden": 0,
@@ -33,34 +69,73 @@
"in_filter": 0,
"in_list_view": 0,
"label": "Email Id",
+ "length": 0,
"no_copy": 0,
"options": "Email",
"permlevel": 0,
"precision": "",
"print_hide": 0,
+ "print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
- "set_only_once": 0
- },
- {
- "fieldname": "login_id_is_different",
- "fieldtype": "Check",
- "label": "Login Id is Different",
- "permlevel": 0,
- "precision": ""
- },
- {
- "depends_on": "login_id_is_different",
- "fieldname": "login_id",
- "fieldtype": "Data",
- "label": "Login Id",
- "permlevel": 0,
- "precision": ""
+ "set_only_once": 0,
+ "unique": 0
},
{
"allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "fieldname": "login_id_is_different",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Login Id is Different",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "depends_on": "login_id_is_different",
+ "fieldname": "login_id",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Login Id",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"fieldname": "password",
"fieldtype": "Password",
"hidden": 0,
@@ -68,18 +143,23 @@
"in_filter": 0,
"in_list_view": 0,
"label": "Password",
+ "length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
+ "print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
- "set_only_once": 0
+ "set_only_once": 0,
+ "unique": 0
},
{
"allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"description": "e.g. \"Support\", \"Sales\", \"Jerry Yang\"",
"fieldname": "email_account_name",
"fieldtype": "Data",
@@ -88,18 +168,23 @@
"in_filter": 0,
"in_list_view": 0,
"label": "Email Account Name",
+ "length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
+ "print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
- "set_only_once": 0
+ "set_only_once": 0,
+ "unique": 0
},
{
"allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"fieldname": "mailbox_settings",
"fieldtype": "Section Break",
"hidden": 0,
@@ -107,18 +192,23 @@
"in_filter": 0,
"in_list_view": 0,
"label": "",
+ "length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
+ "print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
- "set_only_once": 0
+ "set_only_once": 0,
+ "unique": 0
},
{
"allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"default": "",
"description": "Check this to pull emails from your mailbox",
"fieldname": "enable_incoming",
@@ -128,39 +218,74 @@
"in_filter": 0,
"in_list_view": 0,
"label": "Enable Incoming",
+ "length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
+ "print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
- "set_only_once": 0
+ "set_only_once": 0,
+ "unique": 0
},
{
"allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "depends_on": "",
+ "fieldname": "use_imap",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Use IMAP",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"depends_on": "enable_incoming",
- "description": "e.g. pop.gmail.com",
- "fieldname": "pop3_server",
+ "description": "e.g. pop.gmail.com / imap.gmail.com",
+ "fieldname": "email_server",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
- "label": "POP3 Server",
+ "label": "Email Server",
+ "length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
+ "print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
- "set_only_once": 0
+ "set_only_once": 0,
+ "unique": 0
},
{
"allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"depends_on": "enable_incoming",
"fieldname": "use_ssl",
"fieldtype": "Check",
@@ -169,139 +294,382 @@
"in_filter": 0,
"in_list_view": 0,
"label": "Use SSL",
+ "length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
+ "print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
- "set_only_once": 0
+ "set_only_once": 0,
+ "unique": 0
},
{
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"default": "1",
"depends_on": "enable_incoming",
"description": "Ignore attachments over this size",
"fieldname": "attachment_limit",
"fieldtype": "Int",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
"label": "Attachment Limit (MB)",
+ "length": 0,
+ "no_copy": 0,
"permlevel": 0,
- "precision": ""
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
},
{
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"depends_on": "enable_incoming",
"description": "Append as communication against this DocType (must have fields, \"Status\", \"Subject\")",
"fieldname": "append_to",
"fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
"in_list_view": 1,
"label": "Append To",
+ "length": 0,
+ "no_copy": 0,
"options": "DocType",
"permlevel": 0,
- "precision": ""
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
},
{
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"depends_on": "enable_incoming",
"description": "e.g. replies@yourcomany.com. All replies will come to this inbox.",
"fieldname": "default_incoming",
"fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
"label": "Default Incoming",
+ "length": 0,
+ "no_copy": 0,
"permlevel": 0,
- "precision": ""
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
},
{
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"depends_on": "enable_incoming",
"fieldname": "section_break_13",
"fieldtype": "Section Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "length": 0,
+ "no_copy": 0,
"permlevel": 0,
- "precision": ""
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
},
{
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"fieldname": "notify_if_unreplied",
"fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
"label": "Notify if unreplied",
+ "length": 0,
+ "no_copy": 0,
"permlevel": 0,
- "precision": ""
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
},
{
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "default": "30",
"depends_on": "notify_if_unreplied",
"fieldname": "unreplied_for_mins",
"fieldtype": "Int",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
"label": "Notify if unreplied for (in mins)",
+ "length": 0,
+ "no_copy": 0,
"permlevel": 0,
- "precision": ""
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
},
{
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"depends_on": "notify_if_unreplied",
"description": "Email Ids",
"fieldname": "send_notification_to",
"fieldtype": "Small Text",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
"label": "Send Notification to",
+ "length": 0,
+ "no_copy": 0,
"permlevel": 0,
- "precision": ""
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
},
{
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"fieldname": "outgoing_mail_settings",
"fieldtype": "Section Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
"label": "",
+ "length": 0,
+ "no_copy": 0,
"permlevel": 0,
- "precision": ""
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
},
{
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"default": "",
"description": "SMTP Settings for outgoing emails",
"fieldname": "enable_outgoing",
"fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
"label": "Enable Outgoing",
+ "length": 0,
+ "no_copy": 0,
"permlevel": 0,
- "precision": ""
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
},
{
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"depends_on": "enable_outgoing",
"description": "e.g. smtp.gmail.com",
"fieldname": "smtp_server",
"fieldtype": "Data",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
"label": "SMTP Server",
+ "length": 0,
+ "no_copy": 0,
"permlevel": 0,
- "precision": ""
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
},
{
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"depends_on": "enable_outgoing",
"fieldname": "use_tls",
"fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
"label": "Use TLS",
+ "length": 0,
+ "no_copy": 0,
"permlevel": 0,
- "precision": ""
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
},
{
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"depends_on": "enable_outgoing",
"description": "If non standard port (e.g. 587)",
"fieldname": "smtp_port",
"fieldtype": "Data",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
"label": "Port",
+ "length": 0,
+ "no_copy": 0,
"permlevel": 0,
- "precision": ""
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
},
{
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"depends_on": "enable_outgoing",
"description": "Notifications and bulk mails will be sent from this outgoing server.",
"fieldname": "default_outgoing",
"fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
"label": "Default Outgoing",
+ "length": 0,
+ "no_copy": 0,
"permlevel": 0,
- "precision": ""
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
},
{
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"depends_on": "enable_outgoing",
"description": "Uses the Email ID mentioned in this Account as the Sender for all emails sent using this Account. ",
"fieldname": "always_use_account_email_id_as_sender",
"fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
"label": "Always use Account's Email ID as Sender",
+ "length": 0,
+ "no_copy": 0,
"permlevel": 0,
- "precision": ""
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
},
{
"allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"fieldname": "signature_section",
"fieldtype": "Section Break",
"hidden": 0,
@@ -309,26 +677,48 @@
"in_filter": 0,
"in_list_view": 0,
"label": "",
+ "length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
+ "print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
- "set_only_once": 0
- },
- {
- "depends_on": "",
- "fieldname": "add_signature",
- "fieldtype": "Check",
- "label": "Add Signature",
- "permlevel": 0,
- "precision": ""
+ "set_only_once": 0,
+ "unique": 0
},
{
"allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "depends_on": "",
+ "fieldname": "add_signature",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Add Signature",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"depends_on": "add_signature",
"fieldname": "signature",
"fieldtype": "Text Editor",
@@ -337,18 +727,23 @@
"in_filter": 0,
"in_list_view": 0,
"label": "Signature",
+ "length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
+ "print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
- "set_only_once": 0
+ "set_only_once": 0,
+ "unique": 0
},
{
"allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"fieldname": "auto_reply",
"fieldtype": "Section Break",
"hidden": 0,
@@ -356,18 +751,23 @@
"in_filter": 0,
"in_list_view": 0,
"label": "",
+ "length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
+ "print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
- "set_only_once": 0
+ "set_only_once": 0,
+ "unique": 0
},
{
"allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"fieldname": "enable_auto_reply",
"fieldtype": "Check",
"hidden": 0,
@@ -375,19 +775,25 @@
"in_filter": 0,
"in_list_view": 0,
"label": "Enable Auto Reply",
+ "length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
+ "print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
- "set_only_once": 0
+ "set_only_once": 0,
+ "unique": 0
},
{
"allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"depends_on": "enable_auto_reply",
+ "description": "ProTip: Add Reference: {{ reference_doctype }} {{ reference_name }} to send document reference",
"fieldname": "auto_reply_message",
"fieldtype": "Text Editor",
"hidden": 0,
@@ -395,40 +801,79 @@
"in_filter": 0,
"in_list_view": 0,
"label": "Auto Reply Message",
+ "length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
+ "print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
- "set_only_once": 0
+ "set_only_once": 0,
+ "unique": 0
},
{
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"fieldname": "set_footer",
"fieldtype": "Section Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
"label": "",
+ "length": 0,
+ "no_copy": 0,
"permlevel": 0,
- "precision": ""
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
},
{
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"fieldname": "footer",
"fieldtype": "Text Editor",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
"label": "Footer",
+ "length": 0,
+ "no_copy": 0,
"permlevel": 0,
- "precision": ""
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
}
],
"hide_heading": 0,
"hide_toolbar": 0,
"icon": "icon-inbox",
+ "idx": 0,
"in_create": 0,
"in_dialog": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
- "modified": "2015-06-11 00:16:24.026081",
+ "max_attachments": 0,
+ "modified": "2015-12-02 02:27:34.031592",
"modified_by": "Administrator",
"module": "Email",
"name": "Email Account",
@@ -443,6 +888,7 @@
"delete": 1,
"email": 0,
"export": 0,
+ "if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 0,
diff --git a/frappe/email/doctype/email_account/email_account.py b/frappe/email/doctype/email_account/email_account.py
index 04be4ed5cf..668edd54c0 100644
--- a/frappe/email/doctype/email_account/email_account.py
+++ b/frappe/email/doctype/email_account/email_account.py
@@ -3,16 +3,23 @@
from __future__ import unicode_literals
import frappe
+import imaplib
+import re
+import socket
from frappe import _
from frappe.model.document import Document
-from frappe.utils import validate_email_add, cint, get_datetime, DATE_FORMAT, strip
+from frappe.utils import validate_email_add, cint, get_datetime, DATE_FORMAT, strip, comma_or
from frappe.utils.user import is_system_user
+from frappe.utils.jinja import render_template
from frappe.email.smtp import SMTPServer
-from frappe.email.receive import POP3Server, Email
+from frappe.email.receive import EmailServer, Email
from poplib import error_proto
-import markdown2, re
from dateutil.relativedelta import relativedelta
from datetime import datetime, timedelta
+from frappe.desk.form import assign_to
+from frappe.utils.user import get_system_managers
+
+class SentEmailInInbox(Exception): pass
class EmailAccount(Document):
def autoname(self):
@@ -27,7 +34,7 @@ class EmailAccount(Document):
self.name = self.email_account_name
def validate(self):
- """Validate email id and check POP3 and SMTP connections is enabled."""
+ """Validate email id and check POP3/IMAP and SMTP connections is enabled."""
if self.email_id:
validate_email_add(self.email_id, True)
@@ -45,15 +52,22 @@ class EmailAccount(Document):
if not frappe.local.flags.in_install and not frappe.local.flags.in_patch:
if self.enable_incoming:
- self.get_pop3()
+ self.get_server()
if self.enable_outgoing:
self.check_smtp()
if self.notify_if_unreplied:
+ if not self.send_notification_to:
+ frappe.throw(_("{0} is mandatory").format(self.meta.get_label("send_notification_to")))
for e in self.get_unreplied_notification_emails():
validate_email_add(e, True)
+ if self.enable_incoming and self.append_to:
+ valid_doctypes = [d[0] for d in get_append_to()]
+ if self.append_to not in valid_doctypes:
+ frappe.throw(_("Append To can be one of {0}").format(comma_or(valid_doctypes)))
+
def on_update(self):
"""Check there is only one default of each type."""
self.there_must_be_only_one_default()
@@ -86,39 +100,85 @@ class EmailAccount(Document):
)
server.sess
- def get_pop3(self):
+ def get_server(self, in_receive=False):
"""Returns logged in POP3 connection object."""
args = {
- "host": self.pop3_server,
+ "host": self.email_server,
"use_ssl": self.use_ssl,
"username": getattr(self, "login_id", None) or self.email_id,
- "password": self.password
+ "password": self.password,
+ "use_imap": self.use_imap
}
- if not self.pop3_server:
- frappe.throw(_("{0} is required").format("POP3 Server"))
+ if not args.get("host"):
+ frappe.throw(_("{0} is required").format("Email Server"))
- pop3 = POP3Server(frappe._dict(args))
+ email_server = EmailServer(frappe._dict(args))
try:
- pop3.connect()
- except error_proto, e:
- frappe.throw(e.message)
+ email_server.connect()
+ except (error_proto, imaplib.IMAP4.error), e:
+ if in_receive and ("authentication failed" in e.message.lower() or "log in via your web browser" in e.message.lower()):
+ # if called via self.receive and it leads to authentication error, disable incoming
+ # and send email to system manager
+ self.handle_incoming_connect_error(
+ description=_('Authentication failed while receiving emails from Email Account {0}. Message from server: {1}'.format(self.name, e.message))
+ )
+
+ return None
+
+ else:
+ frappe.throw(e.message)
+
+ except socket.error:
+ if in_receive:
+ # timeout while connecting, see receive.py connect method
+ description = frappe.message_log.pop() if frappe.message_log else "Socket Error"
+ self.handle_incoming_connect_error(description=description)
+
+ return None
+
+ else:
+ raise
+
+ return email_server
+
+ def handle_incoming_connect_error(self, description):
+ self.db_set("enable_incoming", 0)
+
+ for user in get_system_managers(only_name=True):
+ try:
+ assign_to.add({
+ 'assign_to': user,
+ 'doctype': self.doctype,
+ 'name': self.name,
+ 'description': description,
+ 'priority': 'High',
+ 'notify': 1
+ })
+ except assign_to.DuplicateToDoError:
+ frappe.message_log.pop()
+ pass
- return pop3
def receive(self, test_mails=None):
- """Called by scheduler to receive emails from this EMail account using POP3."""
+ """Called by scheduler to receive emails from this EMail account using POP3/IMAP."""
if self.enable_incoming:
if frappe.local.flags.in_test:
incoming_mails = test_mails
else:
- pop3 = self.get_pop3()
- incoming_mails = pop3.get_messages()
+ email_server = self.get_server(in_receive=True)
+ if not email_server:
+ return
+
+ incoming_mails = email_server.get_messages()
exceptions = []
for raw in incoming_mails:
try:
- self.insert_communication(raw)
+ communication = self.insert_communication(raw)
+
+ except SentEmailInInbox:
+ frappe.db.rollback()
except Exception:
frappe.db.rollback()
@@ -126,6 +186,8 @@ class EmailAccount(Document):
else:
frappe.db.commit()
+ attachments = [d.file_name for d in communication._attachments]
+ communication.notify(attachments=attachments, fetched_from_email_account=True)
if exceptions:
raise Exception, frappe.as_json(exceptions)
@@ -133,6 +195,11 @@ class EmailAccount(Document):
def insert_communication(self, raw):
email = Email(raw)
+ if email.from_email == self.email_id:
+ # gmail shows sent emails in inbox
+ # and we don't want emails sent by us to be pulled back into the system again
+ raise SentEmailInInbox
+
communication = frappe.get_doc({
"doctype": "Communication",
"subject": email.subject,
@@ -141,6 +208,7 @@ class EmailAccount(Document):
"sender_full_name": email.from_real_name,
"sender": email.from_email,
"recipients": email.mail.get("To"),
+ "cc": email.mail.get("CC"),
"email_account": self.name,
"communication_medium": "Email"
})
@@ -150,15 +218,25 @@ class EmailAccount(Document):
communication.insert(ignore_permissions = 1)
# save attachments
- email.save_attachments_in_doc(communication)
+ communication._attachments = email.save_attachments_in_doc(communication)
+ # replace inline images
+ dirty = False
+ for file in communication._attachments:
+ if file.name in email.cid_map and email.cid_map[file.name]:
+ dirty = True
+ communication.content = communication.content.replace("cid:{0}".format(email.cid_map[file.name]),
+ file.file_url)
+
+ if dirty:
+ # not sure if using save() will trigger anything
+ communication.db_set("content", communication.content)
+
+ # notify all participants of this thread
if self.enable_auto_reply and getattr(communication, "is_first", False):
self.send_auto_reply(communication, email)
- # notify all participants of this thread
- # convert content to HTML - by default text parts of replies are used.
- communication.content = markdown2.markdown(communication.content)
- communication.notify(attachments=email.attachments, except_recipient = True)
+ return communication
def set_thread(self, communication, email):
"""Appends communication to parent based on thread ID. Will extract
@@ -182,23 +260,20 @@ class EmailAccount(Document):
sender_field = None
if in_reply_to:
- if "@" in in_reply_to:
+ if "@{0}".format(frappe.local.site) in in_reply_to:
# reply to a communication sent from the system
- in_reply_to = in_reply_to.split("@", 1)[0]
+ in_reply_to, domain = in_reply_to.split("@", 1)
+
if frappe.db.exists("Communication", in_reply_to):
parent = frappe.get_doc("Communication", in_reply_to)
+ # set in_reply_to of current communication
+ communication.in_reply_to = in_reply_to
+
if parent.reference_name:
- if self.append_to:
- # parent must reference only if name matches
- if parent.reference_doctype==self.append_to:
- # parent same as parent of last communication
- parent = frappe.get_doc(parent.reference_doctype,
- parent.reference_name)
- else:
- parent = frappe.get_doc(parent.reference_doctype,
- parent.reference_name)
+ parent = frappe.get_doc(parent.reference_doctype,
+ parent.reference_name)
if not parent and self.append_to and sender_field:
if subject_field:
@@ -222,18 +297,10 @@ class EmailAccount(Document):
"creation": (">", (get_datetime() - relativedelta(days=10)).strftime(DATE_FORMAT))
}, fields="name")
- else:
- # try and match by sender only
- # as there is no subject field, it implies that threading isn't by subject, but by sender only
-
- parent = frappe.db.get_all(self.append_to, filters={
- sender_field: email.from_email,
- }, fields="name")
-
if parent:
parent = frappe.get_doc(self.append_to, parent[0].name)
- if not parent and self.append_to:
+ if not parent and self.append_to and self.append_to!="Communication":
# no parent found, but must be tagged
# insert parent type doc
parent = frappe.new_doc(self.append_to)
@@ -246,8 +313,17 @@ class EmailAccount(Document):
parent.flags.ignore_mandatory = True
- parent.insert(ignore_permissions=True)
+ try:
+ parent.insert(ignore_permissions=True)
+ except frappe.DuplicateEntryError:
+ # try and find matching parent
+ parent_name = frappe.db.get_value(self.append_to, {sender_field: email.from_email})
+ if parent_name:
+ parent.name = parent_name
+ else:
+ parent = None
+ # NOTE if parent isn't found and there's no subject match, it is likely that it is a new conversation thread and hence is_first = True
communication.is_first = True
if parent:
@@ -256,14 +332,14 @@ class EmailAccount(Document):
def send_auto_reply(self, communication, email):
"""Send auto reply if set."""
- if self.auto_reply_message:
+ if self.enable_auto_reply:
communication.set_incoming_outgoing_accounts()
frappe.sendmail(recipients = [email.from_email],
sender = self.email_id,
reply_to = communication.incoming_email_account,
subject = _("Re: ") + communication.subject,
- content = self.auto_reply_message or \
+ content = render_template(self.auto_reply_message or "", communication.as_dict()) or \
frappe.get_template("templates/emails/auto_reply.html").render(communication.as_dict()),
reference_doctype = communication.reference_doctype,
reference_name = communication.reference_name,
@@ -282,15 +358,14 @@ class EmailAccount(Document):
frappe.db.sql("update `tabCommunication` set email_account='' where email_account=%s", self.name)
@frappe.whitelist()
-def get_append_to(doctype, txt, searchfield, start, page_len, filters):
+def get_append_to(doctype=None, txt=None, searchfield=None, start=None, page_len=None, filters=None):
if not txt: txt = ""
return [[d] for d in frappe.get_hooks("email_append_to") if txt in d]
def pull(now=False):
- """Will be called via scheduler, pull emails from all enabled POP3 email accounts."""
+ """Will be called via scheduler, pull emails from all enabled Email accounts."""
import frappe.tasks
for email_account in frappe.get_list("Email Account", filters={"enable_incoming": 1}):
- #frappe.tasks.pull_from_email_account(frappe.local.site, email_account.name)
if now:
frappe.tasks.pull_from_email_account(frappe.local.site, email_account.name)
else:
diff --git a/frappe/email/doctype/email_account/test_email_account.py b/frappe/email/doctype/email_account/test_email_account.py
index c8c8839e19..87627bb69c 100644
--- a/frappe/email/doctype/email_account/test_email_account.py
+++ b/frappe/email/doctype/email_account/test_email_account.py
@@ -13,6 +13,14 @@ from frappe.email.doctype.email_account.email_account import notify_unreplied
from datetime import datetime, timedelta
class TestEmailAccount(unittest.TestCase):
+ def setUp(self):
+ email_account = frappe.get_doc("Email Account", "_Test Email Account 1")
+ email_account.db_set("enable_incoming", 1)
+
+ def tearDown(self):
+ email_account = frappe.get_doc("Email Account", "_Test Email Account 1")
+ email_account.db_set("enable_incoming", 0)
+
def test_incoming(self):
frappe.db.sql("delete from tabCommunication where sender='test_sender@example.com'")
@@ -41,8 +49,8 @@ class TestEmailAccount(unittest.TestCase):
def test_incoming_with_attach(self):
frappe.db.sql("delete from tabCommunication where sender='test_sender@example.com'")
- existing_file = frappe.get_doc({'doctype': 'File Data', 'file_name': 'erpnext-conf-14.png'})
- frappe.delete_doc("File Data", existing_file.name)
+ existing_file = frappe.get_doc({'doctype': 'File', 'file_name': 'erpnext-conf-14.png'})
+ frappe.delete_doc("File", existing_file.name)
delete_file_from_filesystem(existing_file)
with open(os.path.join(os.path.dirname(__file__), "test_mails", "incoming-2.raw"), "r") as f:
@@ -58,6 +66,11 @@ class TestEmailAccount(unittest.TestCase):
attachments = get_attachments(comm.doctype, comm.name)
self.assertTrue("erpnext-conf-14.png" in [f.file_name for f in attachments])
+ # cleanup
+ existing_file = frappe.get_doc({'doctype': 'File', 'file_name': 'erpnext-conf-14.png'})
+ frappe.delete_doc("File", existing_file.name)
+ delete_file_from_filesystem(existing_file)
+
def test_outgoing(self):
frappe.flags.sent_mail = None
make(subject = "test-mail-000", content="test mail 000", recipients="test_receiver@example.com",
diff --git a/frappe/email/doctype/email_alert/email_alert.json b/frappe/email/doctype/email_alert/email_alert.json
index bc60787f95..b329c4ccae 100644
--- a/frappe/email/doctype/email_alert/email_alert.json
+++ b/frappe/email/doctype/email_alert/email_alert.json
@@ -1,147 +1,457 @@
{
+ "allow_copy": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
"autoname": "hash",
"creation": "2014-07-11 17:18:09.923399",
+ "custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "System",
"fields": [
{
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"default": "1",
"fieldname": "enabled",
"fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
"label": "Enabled",
- "permlevel": 0
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
},
{
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"fieldname": "filters",
"fieldtype": "Section Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
"label": "Filters",
- "permlevel": 0
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
},
{
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "description": "To add dynamic subject, use jinja tags like\n\n",
"fieldname": "subject",
"fieldtype": "Data",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
"in_list_view": 1,
"label": "Subject",
+ "length": 0,
+ "no_copy": 0,
"permlevel": 0,
- "reqd": 1
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
},
{
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"fieldname": "document_type",
"fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
"in_list_view": 1,
"label": "Document Type",
+ "length": 0,
+ "no_copy": 0,
"options": "DocType",
"permlevel": 0,
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "report_hide": 0,
"reqd": 1,
- "search_index": 1
+ "search_index": 1,
+ "set_only_once": 0,
+ "unique": 0
},
{
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"fieldname": "event",
"fieldtype": "Select",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
"in_list_view": 1,
"label": "Send Alert On",
+ "length": 0,
+ "no_copy": 0,
"options": "\nNew\nSave\nSubmit\nCancel\nDays After\nDays Before\nValue Change",
"permlevel": 0,
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "report_hide": 0,
"reqd": 1,
- "search_index": 1
+ "search_index": 1,
+ "set_only_once": 0,
+ "unique": 0
},
{
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"depends_on": "eval:doc.event==\"Days After\" || doc.event==\"Days Before\"",
"description": "Send alert if date matches this field's value",
"fieldname": "date_changed",
"fieldtype": "Select",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
"label": "Reference Date",
- "permlevel": 0
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
},
{
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"default": "0",
"depends_on": "eval:doc.event==\"Days After\" || doc.event==\"Days Before\"",
"description": "Send days before or after the reference date",
"fieldname": "days_in_advance",
"fieldtype": "Int",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
"label": "Days Before or After",
- "permlevel": 0
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
},
{
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"depends_on": "eval:doc.event==\"Value Change\"",
"description": "Send alert if this field's value changes",
"fieldname": "value_changed",
"fieldtype": "Select",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
"label": "Value Changed",
- "permlevel": 0
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
},
{
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"depends_on": "",
"description": "Optional: The alert will be sent if this expression is true",
"fieldname": "condition",
"fieldtype": "Data",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
"in_list_view": 1,
"label": "Condition",
- "permlevel": 0
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
},
{
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"fieldname": "column_break_6",
"fieldtype": "Column Break",
- "permlevel": 0
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
},
{
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"fieldname": "html_7",
"fieldtype": "HTML",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "length": 0,
+ "no_copy": 0,
"options": "Condition Examples:
\ndoc.status==\"Open\"\ndoc.due_date==nowdate()\ndoc.total > 40000\n \nHints:
\n\nTo check for an event every day, select \"Date Change\" in Event \nTo send an alert if a particular value changes, select \"Value Change\" \n ",
- "permlevel": 0
+ "permlevel": 0,
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
},
{
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"fieldname": "column_break_5",
"fieldtype": "Section Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
"label": "Recipients",
- "permlevel": 0
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
},
{
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"fieldname": "recipients",
"fieldtype": "Table",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
"label": "Recipients",
+ "length": 0,
+ "no_copy": 0,
"options": "Email Alert Recipient",
"permlevel": 0,
- "reqd": 1
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
},
{
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"fieldname": "message_sb",
"fieldtype": "Section Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
"label": "Message",
- "permlevel": 0
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
},
{
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"fieldname": "message",
"fieldtype": "Text",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
"label": "Message",
+ "length": 0,
+ "no_copy": 0,
"permlevel": 0,
- "reqd": 1
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
},
{
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"fieldname": "attach_print",
"fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
"label": "Attach Print",
+ "length": 0,
+ "no_copy": 0,
"permlevel": 0,
- "precision": ""
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
},
{
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"fieldname": "message_examples",
"fieldtype": "HTML",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
"label": "Message Examples",
- "options": "Message Example (Markdown) \nTransaction {{ doc.name }} has exceeded Due Date. Please take relevant action\n\n#### Details\n\nCustomer: {{ doc.customer }}\nAmount: {{ doc.total_amount }} ",
- "permlevel": 0
+ "length": 0,
+ "no_copy": 0,
+ "options": "Message Example \n\n\n<h3>Order Overdue</h3>\n\n<p>Transaction {{ doc.name }} has exceeded Due Date. Please take necessary action.</p>\n\n<!-- show last comment -->\n{% if comments %}\nLast comment: {{ comments[-1].comment }} by {{ comments[-1].by }}\n{% endif %}\n\n<h4>Details</h4>\n\n<ul>\n<li>Customer: {{ doc.customer }}\n<li>Amount: {{ doc.total_amount }}\n</ul>\n ",
+ "permlevel": 0,
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
},
{
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"fieldname": "view_properties",
"fieldtype": "Button",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
"label": "View Properties (via Customize Form)",
+ "length": 0,
+ "no_copy": 0,
"permlevel": 0,
- "precision": ""
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
}
],
+ "hide_heading": 0,
+ "hide_toolbar": 0,
"icon": "icon-envelope",
- "modified": "2015-03-25 06:20:07.472953",
+ "idx": 0,
+ "in_create": 0,
+ "in_dialog": 0,
+ "is_submittable": 0,
+ "issingle": 0,
+ "istable": 0,
+ "max_attachments": 0,
+ "menu_index": 0,
+ "modified": "2015-11-26 02:14:59.637519",
"modified_by": "Administrator",
"module": "Email",
"name": "Email Alert",
@@ -149,18 +459,28 @@
"owner": "Administrator",
"permissions": [
{
+ "amend": 0,
+ "apply_user_permissions": 0,
+ "cancel": 0,
"create": 1,
"delete": 1,
+ "email": 0,
"export": 1,
+ "if_owner": 0,
"import": 0,
"permlevel": 0,
+ "print": 0,
"read": 1,
"report": 1,
"role": "System Manager",
+ "set_user_permissions": 0,
"share": 1,
+ "submit": 0,
"write": 1
}
],
+ "read_only": 0,
+ "read_only_onload": 0,
"sort_field": "modified",
"sort_order": "DESC",
"title_field": "subject"
diff --git a/frappe/email/doctype/email_alert/email_alert.py b/frappe/email/doctype/email_alert/email_alert.py
index 4b4065791f..5da08920c8 100644
--- a/frappe/email/doctype/email_alert/email_alert.py
+++ b/frappe/email/doctype/email_alert/email_alert.py
@@ -3,6 +3,7 @@
from __future__ import unicode_literals
import frappe
+import json
from frappe import _
from frappe.model.document import Document
from frappe.utils import validate_email_add, nowdate
@@ -94,7 +95,22 @@ def evaluate_alert(doc, alert, event):
if not recipients:
return
- frappe.sendmail(recipients=recipients, subject=alert.subject,
- message= frappe.render_template(alert.message, {"doc": doc, "alert":alert}),
+ subject = alert.subject
+
+ if event != "Value Change" and not doc.is_new():
+ # reload the doc for the latest values & comments,
+ # except for validate type event.
+ doc = frappe.get_doc(doc.doctype, doc.name)
+
+ context = {"doc": doc, "alert": alert, "comments": None}
+
+ if doc.get("_comments"):
+ context["comments"] = json.loads(doc.get("_comments"))
+
+ if "{" in subject:
+ subject = frappe.render_template(alert.subject, context)
+
+ frappe.sendmail(recipients=recipients, subject=subject,
+ message= frappe.render_template(alert.message, context),
bulk=True, reference_doctype = doc.doctype, reference_name = doc.name,
attachments = [frappe.attach_print(doc.doctype, doc.name)] if alert.attach_print else None)
diff --git a/frappe/email/doctype/email_alert_recipient/email_alert_recipient.json b/frappe/email/doctype/email_alert_recipient/email_alert_recipient.json
index 519228e97e..c28dc54e22 100644
--- a/frappe/email/doctype/email_alert_recipient/email_alert_recipient.json
+++ b/frappe/email/doctype/email_alert_recipient/email_alert_recipient.json
@@ -1,42 +1,100 @@
{
- "creation": "2014-07-11 17:19:37.037109",
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "",
+ "allow_copy": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "creation": "2014-07-11 17:19:37.037109",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
"fields": [
{
- "description": "Optional: Alert will only be sent if value is a valid email id.",
- "fieldname": "email_by_document_field",
- "fieldtype": "Select",
- "in_list_view": 1,
- "label": "Email By Document Field",
- "permlevel": 0
- },
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "description": "Optional: Alert will only be sent if value is a valid email id.",
+ "fieldname": "email_by_document_field",
+ "fieldtype": "Select",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 1,
+ "label": "Email By Document Field",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
{
- "description": "Optional: Always send to these ids. Each email id on a new row",
- "fieldname": "cc",
- "fieldtype": "Text",
- "in_list_view": 1,
- "label": "CC",
- "permlevel": 0
- },
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "description": "Optional: Always send to these ids. Each email id on a new row",
+ "fieldname": "cc",
+ "fieldtype": "Text",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 1,
+ "label": "CC",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
{
- "description": "Expression, Optional",
- "fieldname": "condition",
- "fieldtype": "Data",
- "in_list_view": 1,
- "label": "Condition",
- "permlevel": 0
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "description": "Expression, Optional",
+ "fieldname": "condition",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 1,
+ "label": "Condition",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
}
- ],
- "istable": 1,
- "modified": "2014-07-11 17:54:53.298536",
- "modified_by": "Administrator",
- "module": "Email",
- "name": "Email Alert Recipient",
- "name_case": "",
- "owner": "Administrator",
- "permissions": [],
- "sort_field": "modified",
+ ],
+ "hide_heading": 0,
+ "hide_toolbar": 0,
+ "in_create": 0,
+ "in_dialog": 0,
+ "is_submittable": 0,
+ "issingle": 0,
+ "istable": 1,
+ "max_attachments": 0,
+ "modified": "2015-11-16 06:29:46.092268",
+ "modified_by": "Administrator",
+ "module": "Email",
+ "name": "Email Alert Recipient",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [],
+ "read_only": 0,
+ "read_only_onload": 0,
+ "sort_field": "modified",
"sort_order": "DESC"
-}
+}
\ No newline at end of file
diff --git a/frappe/email/doctype/email_unsubscribe/email_unsubscribe.json b/frappe/email/doctype/email_unsubscribe/email_unsubscribe.json
index a70c363034..71ea8cc2db 100644
--- a/frappe/email/doctype/email_unsubscribe/email_unsubscribe.json
+++ b/frappe/email/doctype/email_unsubscribe/email_unsubscribe.json
@@ -10,6 +10,8 @@
"fields": [
{
"allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"fieldname": "email",
"fieldtype": "Data",
"hidden": 0,
@@ -17,6 +19,7 @@
"in_filter": 0,
"in_list_view": 1,
"label": "Email",
+ "length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
@@ -25,10 +28,13 @@
"report_hide": 0,
"reqd": 1,
"search_index": 0,
- "set_only_once": 0
+ "set_only_once": 0,
+ "unique": 0
},
{
"allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"fieldname": "reference_doctype",
"fieldtype": "Link",
"hidden": 0,
@@ -36,6 +42,7 @@
"in_filter": 0,
"in_list_view": 1,
"label": "Reference DocType",
+ "length": 0,
"no_copy": 0,
"options": "DocType",
"permlevel": 0,
@@ -43,12 +50,15 @@
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
- "reqd": 1,
+ "reqd": 0,
"search_index": 0,
- "set_only_once": 0
+ "set_only_once": 0,
+ "unique": 0
},
{
"allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"fieldname": "reference_name",
"fieldtype": "Dynamic Link",
"hidden": 0,
@@ -56,6 +66,7 @@
"in_filter": 0,
"in_list_view": 1,
"label": "Reference Name",
+ "length": 0,
"no_copy": 0,
"options": "reference_doctype",
"permlevel": 0,
@@ -63,9 +74,33 @@
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
- "reqd": 1,
+ "reqd": 0,
"search_index": 0,
- "set_only_once": 0
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "fieldname": "global_unsubscribe",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 1,
+ "label": "Global Unsubscribe",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
}
],
"hide_heading": 0,
@@ -75,7 +110,8 @@
"is_submittable": 0,
"issingle": 0,
"istable": 0,
- "modified": "2015-03-18 09:41:20.216319",
+ "max_attachments": 0,
+ "modified": "2015-11-16 06:29:46.223148",
"modified_by": "Administrator",
"module": "Email",
"name": "Email Unsubscribe",
@@ -90,6 +126,7 @@
"delete": 1,
"email": 1,
"export": 1,
+ "if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
diff --git a/frappe/email/doctype/email_unsubscribe/email_unsubscribe.py b/frappe/email/doctype/email_unsubscribe/email_unsubscribe.py
index 02d3569988..2f879f98ee 100644
--- a/frappe/email/doctype/email_unsubscribe/email_unsubscribe.py
+++ b/frappe/email/doctype/email_unsubscribe/email_unsubscribe.py
@@ -8,6 +8,32 @@ from frappe.model.document import Document
from frappe import _
class EmailUnsubscribe(Document):
+ def validate(self):
+ if not self.global_unsubscribe and not (self.reference_doctype and self.reference_name):
+ frappe.throw(_("Reference DocType and Reference Name are required"), frappe.MandatoryError)
+
+ if not self.global_unsubscribe and frappe.db.get_value(self.doctype, self.name, "global_unsubscribe"):
+ frappe.throw(_("Delete this record to allow sending to this email address"))
+
+ if self.global_unsubscribe:
+ if frappe.get_all("Email Unsubscribe",
+ filters={"email": self.email, "global_unsubscribe": 1, "name": ["!=", self.name]}):
+ frappe.throw(_("{0} already unsubscribed").format(self.email), frappe.DuplicateEntryError)
+
+ else:
+ if frappe.get_all("Email Unsubscribe",
+ filters={
+ "email": self.email,
+ "reference_doctype": self.reference_doctype,
+ "reference_name": self.reference_name,
+ "name": ["!=", self.name]
+ }):
+ frappe.throw(_("{0} already unsubscribed for {1} {2}").format(
+ self.email, self.reference_doctype, self.reference_name),
+ frappe.DuplicateEntryError)
+
def on_update(self):
- doc = frappe.get_doc(self.reference_doctype, self.reference_name)
- doc.add_comment("Label", _("Left this conversation"), comment_by=self.email)
+ if self.reference_doctype and self.reference_name:
+ doc = frappe.get_doc(self.reference_doctype, self.reference_name)
+ doc.add_comment("Label", _("Left this conversation"), comment_by=self.email)
+
diff --git a/frappe/email/doctype/standard_reply/standard_reply.json b/frappe/email/doctype/standard_reply/standard_reply.json
index 0bb51fc71b..dbe3a5f776 100644
--- a/frappe/email/doctype/standard_reply/standard_reply.json
+++ b/frappe/email/doctype/standard_reply/standard_reply.json
@@ -1,39 +1,93 @@
{
+ "allow_copy": 0,
"allow_import": 1,
+ "allow_rename": 1,
"autoname": "field:subject",
"creation": "2014-06-19 05:20:26.331041",
+ "custom": 0,
"docstatus": 0,
"doctype": "DocType",
- "document_type": "Transaction",
+ "document_type": "Document",
"fields": [
{
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"fieldname": "subject",
"fieldtype": "Data",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
"in_list_view": 1,
"label": "Subject",
+ "length": 0,
+ "no_copy": 0,
"permlevel": 0,
- "reqd": 1
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
},
{
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"fieldname": "response",
"fieldtype": "Text Editor",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
"in_list_view": 1,
"label": "Response",
+ "length": 0,
+ "no_copy": 0,
"permlevel": 0,
- "reqd": 1
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
},
{
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"default": "user",
"fieldname": "owner",
"fieldtype": "Link",
"hidden": 1,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
"label": "Owner",
+ "length": 0,
+ "no_copy": 0,
"options": "User",
- "permlevel": 0
+ "permlevel": 0,
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
}
],
+ "hide_heading": 0,
+ "hide_toolbar": 0,
"icon": "icon-comment",
- "modified": "2015-02-05 05:11:46.922356",
+ "in_create": 0,
+ "in_dialog": 0,
+ "is_submittable": 0,
+ "issingle": 0,
+ "istable": 0,
+ "max_attachments": 0,
+ "modified": "2015-11-16 06:29:57.875243",
"modified_by": "Administrator",
"module": "Email",
"name": "Standard Reply",
@@ -41,33 +95,48 @@
"owner": "Administrator",
"permissions": [
{
- "permlevel": 0,
- "read": 1,
- "role": "All"
- },
- {
- "apply_user_permissions": 1,
+ "amend": 0,
+ "apply_user_permissions": 0,
+ "cancel": 0,
"create": 1,
+ "delete": 0,
+ "email": 0,
+ "export": 0,
+ "if_owner": 0,
+ "import": 0,
"permlevel": 0,
+ "print": 0,
"read": 1,
+ "report": 0,
"role": "All",
+ "set_user_permissions": 0,
"share": 1,
+ "submit": 0,
"write": 1
},
{
+ "amend": 0,
+ "apply_user_permissions": 0,
+ "cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
+ "if_owner": 0,
"import": 1,
"permlevel": 0,
+ "print": 0,
"read": 1,
"report": 1,
"role": "System Manager",
+ "set_user_permissions": 0,
"share": 1,
+ "submit": 0,
"write": 1
}
],
+ "read_only": 0,
+ "read_only_onload": 0,
"sort_field": "modified",
"sort_order": "DESC"
}
\ No newline at end of file
diff --git a/frappe/email/doctype/standard_reply/test_standard_reply.py b/frappe/email/doctype/standard_reply/test_standard_reply.py
new file mode 100644
index 0000000000..9255716b12
--- /dev/null
+++ b/frappe/email/doctype/standard_reply/test_standard_reply.py
@@ -0,0 +1,12 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import frappe
+import unittest
+
+# test_records = frappe.get_test_records('Standard Reply')
+
+class TestStandardReply(unittest.TestCase):
+ pass
diff --git a/frappe/email/email_body.py b/frappe/email/email_body.py
index c178cc21ff..66522d1d7f 100644
--- a/frappe/email/email_body.py
+++ b/frappe/email/email_body.py
@@ -5,7 +5,7 @@ from __future__ import unicode_literals
import frappe
from frappe.utils.pdf import get_pdf
from frappe.email.smtp import get_outgoing_email_account
-from frappe.utils import get_url, scrub_urls, strip, expand_relative_urls, cint
+from frappe.utils import get_url, scrub_urls, strip, expand_relative_urls, cint, split_emails
import email.utils
from markdown2 import markdown
@@ -42,7 +42,7 @@ class EMail:
if isinstance(recipients, basestring):
recipients = recipients.replace(';', ',').replace('\n', '')
- recipients = recipients.split(',')
+ recipients = split_emails(recipients)
# remove null
recipients = filter(None, (strip(r) for r in recipients))
@@ -161,8 +161,7 @@ class EMail:
self.add_attachment(name, get_pdf(html, options), 'application/octet-stream')
def get_default_sender(self):
- email_account = get_outgoing_email_account()
- return email.utils.formataddr((email_account.name, email_account.get("sender") or email_account.get("email_id")))
+ return get_outgoing_email_account().default_sender
def validate(self):
"""validate the email ids"""
@@ -192,7 +191,7 @@ class EMail:
"Date": email.utils.formatdate(),
"Reply-To": self.reply_to.encode("utf-8") if self.reply_to else None,
"CC": ', '.join(self.cc).encode("utf-8") if self.cc else None,
- b'X-Frappe-Site': get_url().encode('utf-8')
+ b'X-Frappe-Site': get_url().encode('utf-8'),
}
# reset headers as values may be changed.
@@ -201,6 +200,10 @@ class EMail:
del self.msg_root[key]
self.msg_root[key] = val
+ # call hook to enable apps to modify msg_root before sending
+ for hook in frappe.get_hooks("make_email_body_message"):
+ frappe.get_attr(hook)(self)
+
def as_string(self):
"""validate, build message and convert to string"""
self.validate()
@@ -234,18 +237,18 @@ def get_footer(email_account, footer=None):
footer = footer or ""
if email_account and email_account.footer:
- footer += email_account.footer
+ footer += '{0}
'.format(email_account.footer)
footer += ""
company_address = frappe.db.get_default("email_footer_address")
if company_address:
- footer += '{0}
'\
+ footer += '{0}
'\
.format(company_address.replace("\n", " "))
if not cint(frappe.db.get_default("disable_standard_email_footer")):
for default_mail_footer in frappe.get_hooks("default_mail_footer"):
- footer += default_mail_footer
+ footer += '{0}
'.format(default_mail_footer)
return footer
diff --git a/frappe/email/receive.py b/frappe/email/receive.py
index 5078cfeea9..135c1d3367 100644
--- a/frappe/email/receive.py
+++ b/frappe/email/receive.py
@@ -3,7 +3,7 @@
from __future__ import unicode_literals
import time
-import _socket, poplib
+import _socket, poplib, imaplib
import frappe
from frappe import _
from frappe.utils import extract_email_id, convert_utc_to_user_timezone, now, cint, cstr, strip
@@ -17,7 +17,7 @@ class EmailTimeoutError(frappe.ValidationError): pass
class TotalSizeExceededError(frappe.ValidationError): pass
class LoginLimitExceeded(frappe.ValidationError): pass
-class POP3Server:
+class EmailServer:
"""Wrapper for POP server to pull emails."""
def __init__(self, args=None):
self.setup(args)
@@ -36,6 +36,33 @@ class POP3Server:
def connect(self):
"""Connect to **Email Account**."""
+ if cint(self.settings.use_imap):
+ return self.connect_imap()
+ else:
+ return self.connect_pop()
+
+ def connect_imap(self):
+ """Connect to IMAP"""
+ try:
+ if cint(self.settings.use_ssl):
+ self.imap = Timed_IMAP4_SSL(self.settings.host, timeout=frappe.conf.get("pop_timeout"))
+ else:
+ self.imap = Timed_IMAP4(self.settings.host, timeout=frappe.conf.get("pop_timeout"))
+ self.imap.login(self.settings.username, self.settings.password)
+ # connection established!
+ return True
+
+ except _socket.error:
+ # Invalid mail server -- due to refusing connection
+ frappe.msgprint(_('Invalid Mail Server. Please rectify and try again.'))
+ raise
+
+ except Exception, e:
+ frappe.msgprint(_('Cannot connect: {0}').format(str(e)))
+ raise
+
+ def connect_pop(self):
+ #this method return pop connection
try:
if cint(self.settings.use_ssl):
self.pop = Timed_POP3_SSL(self.settings.host, timeout=frappe.conf.get("pop_timeout"))
@@ -49,6 +76,9 @@ class POP3Server:
return True
except _socket.error:
+ # log performs rollback and logs error in scheduler log
+ log("receive.connect_pop")
+
# Invalid mail server -- due to refusing connection
frappe.msgprint(_('Invalid Mail Server. Please rectify and try again.'))
raise
@@ -75,8 +105,9 @@ class POP3Server:
# track if errors arised
self.errors = False
self.latest_messages = []
- pop_list = self.pop.list()[1]
- num = num_copy = len(pop_list)
+
+ email_list = self.get_new_mails()
+ num = num_copy = len(email_list)
# WARNING: Hard coded max no. of messages to be popped
if num > 20: num = 20
@@ -86,22 +117,23 @@ class POP3Server:
self.max_email_size = cint(frappe.local.conf.get("max_email_size"))
self.max_total_size = 5 * self.max_email_size
- for i, pop_meta in enumerate(pop_list):
+ for i, message_meta in enumerate(email_list):
# do not pull more than NUM emails
if (i+1) > num:
break
try:
- self.retrieve_message(pop_meta, i+1)
+ self.retrieve_message(message_meta, i+1)
except (TotalSizeExceededError, EmailTimeoutError, LoginLimitExceeded):
break
# WARNING: Mark as read - message number 101 onwards from the pop list
# This is to avoid having too many messages entering the system
num = num_copy
- if num > 100 and not self.errors:
- for m in xrange(101, num+1):
- self.pop.dele(m)
+ if not cint(self.settings.use_imap):
+ if num > 100 and not self.errors:
+ for m in xrange(101, num+1):
+ self.pop.dele(m)
except Exception, e:
if self.has_login_limit_exceeded(e):
@@ -112,17 +144,35 @@ class POP3Server:
finally:
# no matter the exception, pop should quit if connected
- self.pop.quit()
+ if cint(self.settings.use_imap):
+ self.imap.logout()
+ else:
+ self.pop.quit()
return self.latest_messages
- def retrieve_message(self, pop_meta, msg_num):
+ def get_new_mails(self):
+ """Return list of new mails"""
+ if cint(self.settings.use_imap):
+ self.imap.select("Inbox")
+ response, message = self.imap.uid('search', None, "UNSEEN")
+ email_list = message[0].split()
+ else:
+ email_list = self.pop.list()[1]
+
+ return email_list
+
+ def retrieve_message(self, message_meta, msg_num=None):
incoming_mail = None
try:
- self.validate_pop(pop_meta)
- msg = self.pop.retr(msg_num)
+ self.validate_message_limits(message_meta)
- self.latest_messages.append(b'\n'.join(msg[1]))
+ if cint(self.settings.use_imap):
+ status, message = self.imap.uid('fetch', message_meta, '(RFC822)')
+ self.latest_messages.append(message[0][1])
+ else:
+ msg = self.pop.retr(msg_num)
+ self.latest_messages.append(b'\n'.join(msg[1]))
except (TotalSizeExceededError, EmailTimeoutError):
# propagate this error to break the loop
@@ -140,9 +190,11 @@ class POP3Server:
self.errors = True
frappe.db.rollback()
- self.pop.dele(msg_num)
+ if not cint(self.settings.use_imap):
+ self.pop.dele(msg_num)
else:
- self.pop.dele(msg_num)
+ if not cint(self.settings.use_imap):
+ self.pop.dele(msg_num)
def has_login_limit_exceeded(self, e):
return "-ERR Exceeded the login limit" in strip(cstr(e.message))
@@ -153,16 +205,16 @@ class POP3Server:
"Connection timed out",
)
for message in messages:
- if message in strip(cstr(e.message)):
+ if message in strip(cstr(e.message)) or message in strip(cstr(getattr(e, 'strerror', ''))):
return True
return False
- def validate_pop(self, pop_meta):
+ def validate_message_limits(self, message_meta):
# throttle based on email size
if not self.max_email_size:
return
- m, size = pop_meta.split()
+ m, size = message_meta.split()
size = cint(size)
if size < self.max_email_size:
@@ -203,6 +255,7 @@ class Email:
self.text_content = ''
self.html_content = ''
self.attachments = []
+ self.cid_map = {}
self.parse()
self.set_content_and_type()
self.set_subject()
@@ -293,13 +346,24 @@ class Email:
'fcontent': fcontent,
})
+ cid = (part.get("Content-Id") or "").strip("><")
+ if cid:
+ self.cid_map[fname] = cid
+
def save_attachments_in_doc(self, doc):
"""Save email attachments in given document."""
from frappe.utils.file_manager import save_file, MaxFileSizeReachedError
+ saved_attachments = []
+
for attachment in self.attachments:
try:
- save_file(attachment['fname'], attachment['fcontent'],
- doc.doctype, doc.name)
+ file_data = save_file(attachment['fname'], attachment['fcontent'],
+ doc.doctype, doc.name, is_private=1)
+ saved_attachments.append(file_data)
+
+ if attachment['fname'] in self.cid_map:
+ self.cid_map[file_data.name] = self.cid_map[attachment['fname']]
+
except MaxFileSizeReachedError:
# WARNING: bypass max file size exception
pass
@@ -307,6 +371,8 @@ class Email:
# same file attached twice??
pass
+ return saved_attachments
+
def get_thread_id(self):
"""Extract thread ID from `[]`"""
import re
@@ -341,3 +407,8 @@ class Timed_POP3(TimerMixin, poplib.POP3):
class Timed_POP3_SSL(TimerMixin, poplib.POP3_SSL):
_super = poplib.POP3_SSL
+class Timed_IMAP4(TimerMixin, imaplib.IMAP4):
+ _super = imaplib.IMAP4
+
+class Timed_IMAP4_SSL(TimerMixin, imaplib.IMAP4_SSL):
+ _super = imaplib.IMAP4_SSL
diff --git a/frappe/email/smtp.py b/frappe/email/smtp.py
index 0fbf693095..7554573370 100644
--- a/frappe/email/smtp.py
+++ b/frappe/email/smtp.py
@@ -5,6 +5,7 @@ from __future__ import unicode_literals
import frappe
import smtplib
+import email.utils
import _socket
from frappe.utils import cint
from frappe import _
@@ -15,7 +16,7 @@ def send(email, append_to=None):
frappe.flags.sent_mail = email.as_string()
return
- if frappe.flags.mute_emails or frappe.conf.get("mute_emails") or False:
+ if frappe.are_emails_muted():
frappe.msgprint(_("Emails are muted"))
return
@@ -55,7 +56,12 @@ def get_outgoing_email_account(raise_exception_not_set=True, append_to=None):
email_account = get_default_outgoing_email_account(raise_exception_not_set=raise_exception_not_set)
if not email_account and raise_exception_not_set:
- frappe.throw(_("Please setup default Email Account from Setup > Email > Email Account"))
+ frappe.throw(_("Please setup default Email Account from Setup > Email > Email Account"),
+ frappe.OutgoingEmailError)
+
+ if email_account:
+ email_account.default_sender = email.utils.formataddr((email_account.name,
+ email_account.get("sender") or email_account.get("email_id")))
frappe.local.outgoing_email_account[append_to or "default"] = email_account
@@ -76,11 +82,12 @@ def get_default_outgoing_email_account(raise_exception_not_set=True):
"sender": frappe.conf.get("auto_email_id", "notifications@example.com")
})
email_account.from_site_config = True
+ email_account.name = frappe.conf.get("email_sender_name") or "Frappe"
if not email_account and not raise_exception_not_set:
return None
- if frappe.flags.mute_emails or frappe.conf.get("mute_emails") or False:
+ if frappe.are_emails_muted():
# create a stub
email_account = frappe.new_doc("Email Account")
email_account.update({
diff --git a/frappe/exceptions.py b/frappe/exceptions.py
index cd67366ff2..bdb6eb07a5 100644
--- a/frappe/exceptions.py
+++ b/frappe/exceptions.py
@@ -35,6 +35,9 @@ class UnsupportedMediaType(Exception):
class Redirect(Exception):
http_status_code = 301
+class CSRFTokenError(Exception):
+ http_status_code = 400
+
class DuplicateEntryError(NameError):pass
class DataError(ValidationError): pass
class UnknownDomainError(Exception): pass
@@ -44,6 +47,7 @@ class MandatoryError(ValidationError): pass
class InvalidSignatureError(ValidationError): pass
class RateLimitExceededError(ValidationError): pass
class CannotChangeConstantError(ValidationError): pass
+class CharacterLengthExceededError(ValidationError): pass
class UpdateAfterSubmitError(ValidationError): pass
class LinkValidationError(ValidationError): pass
class CancelledLinkError(LinkValidationError): pass
@@ -53,3 +57,5 @@ class EmptyTableError(ValidationError): pass
class LinkExistsError(ValidationError): pass
class InvalidEmailAddressError(ValidationError): pass
class TemplateNotFoundError(ValidationError): pass
+class UniqueValidationError(ValidationError): pass
+class AppNotInstalledError(ValidationError): pass
diff --git a/frappe/frappeclient.py b/frappe/frappeclient.py
index 3a83c507ce..8a4c257951 100644
--- a/frappe/frappeclient.py
+++ b/frappe/frappeclient.py
@@ -177,8 +177,8 @@ class FrappeClient(object):
self.migrate_doctype("Comment", {"comment_doctype": doctype, "comment_docname": doc["name"]},
update={"comment_docname": new_doc.name}, verbose=0)
- if doctype != "File Data":
- self.migrate_doctype("File Data", {"attached_to_doctype": doctype,
+ if doctype != "File":
+ self.migrate_doctype("File", {"attached_to_doctype": doctype,
"attached_to_name": doc["name"]}, update={"attached_to_name": new_doc.name}, verbose=0)
def migrate_single(self, doctype):
diff --git a/frappe/geo/country_info.json b/frappe/geo/country_info.json
index f33977c6b2..d1d6531cc3 100644
--- a/frappe/geo/country_info.json
+++ b/frappe/geo/country_info.json
@@ -310,12 +310,13 @@
},
"Bosnia and Herzegovina": {
"code": "ba",
+ "currency": "BAM",
"currency_fraction": "Fening",
"currency_fraction_units": 100,
- "currency_symbol": "KM or \u041a\u041c",
- "number_format": "#,###.##",
+ "currency_symbol": "KM",
+ "number_format": "#.###,##",
"timezones": [
- "Europe/Belgrade"
+ "Europe/Sarajevo"
]
},
"Botswana": {
@@ -625,7 +626,7 @@
"currency_symbol": "kn",
"number_format": "#.###,##",
"timezones": [
- "Europe/Belgrade"
+ "Europe/Zagreb"
]
},
"Cuba": {
@@ -911,6 +912,7 @@
},
"Ghana": {
"code": "gh",
+ "currency": "GHS",
"currency_fraction": "Pesewa",
"currency_fraction_units": 100,
"currency_symbol": "\u20b5",
@@ -2565,7 +2567,11 @@
},
"Venezuela, Bolivarian Republic of": {
"code": "ve",
- "number_format": "#,###.##"
+ "number_format": "#.###,##",
+ "currency": "VEF",
+ "currency_symbol": "Bs.",
+ "currency_fraction": "Centimos",
+ "currency_fraction_units": 100
},
"Vietnam": {
"code": "vn",
diff --git a/frappe/geo/doctype/country/country.json b/frappe/geo/doctype/country/country.json
index d763eb7818..e2e03b5ebe 100644
--- a/frappe/geo/doctype/country/country.json
+++ b/frappe/geo/doctype/country/country.json
@@ -1,48 +1,121 @@
{
+ "allow_copy": 0,
"allow_import": 1,
"allow_rename": 1,
"autoname": "field:country_name",
"creation": "2013-01-19 10:23:30",
+ "custom": 0,
"docstatus": 0,
"doctype": "DocType",
- "document_type": "Master",
+ "document_type": "Setup",
"fields": [
{
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"fieldname": "country_name",
"fieldtype": "Data",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
"in_list_view": 1,
"label": "Country Name",
+ "length": 0,
+ "no_copy": 0,
"oldfieldname": "country_name",
"oldfieldtype": "Data",
"permlevel": 0,
- "reqd": 1
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
},
{
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"fieldname": "date_format",
"fieldtype": "Data",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
"in_list_view": 1,
"label": "Date Format",
- "permlevel": 0
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
},
{
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"fieldname": "time_zones",
"fieldtype": "Text",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
"in_list_view": 1,
"label": "Time Zones",
- "permlevel": 0
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
},
{
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"fieldname": "code",
"fieldtype": "Data",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
"in_list_view": 1,
"label": "Code",
- "permlevel": 0
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
}
],
+ "hide_heading": 0,
+ "hide_toolbar": 0,
"icon": "icon-globe",
"idx": 1,
"in_create": 0,
- "modified": "2015-02-05 05:11:36.234753",
+ "in_dialog": 0,
+ "is_submittable": 0,
+ "issingle": 0,
+ "istable": 0,
+ "max_attachments": 0,
+ "menu_index": 0,
+ "modified": "2015-12-16 02:12:12.092442",
"modified_by": "Administrator",
"module": "Geo",
"name": "Country",
@@ -50,26 +123,47 @@
"permissions": [
{
"amend": 0,
+ "apply_user_permissions": 0,
+ "cancel": 0,
"create": 1,
+ "delete": 0,
"email": 1,
+ "export": 0,
+ "if_owner": 0,
+ "import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
+ "set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
},
{
- "apply_user_permissions": 1,
+ "amend": 0,
+ "apply_user_permissions": 0,
+ "cancel": 0,
+ "create": 0,
+ "delete": 0,
"email": 1,
+ "export": 0,
+ "if_owner": 0,
+ "import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
- "role": "All"
+ "role": "All",
+ "set_user_permissions": 0,
+ "share": 0,
+ "submit": 0,
+ "write": 0
}
],
- "read_only": 0
+ "read_only": 0,
+ "read_only_onload": 0,
+ "sort_field": "country_name",
+ "sort_order": "ASC"
}
\ No newline at end of file
diff --git a/frappe/geo/doctype/currency/currency.json b/frappe/geo/doctype/currency/currency.json
index 48bb30ac26..379d07e8db 100644
--- a/frappe/geo/doctype/currency/currency.json
+++ b/frappe/geo/doctype/currency/currency.json
@@ -1,64 +1,166 @@
{
+ "allow_copy": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
"autoname": "field:currency_name",
"creation": "2013-01-28 10:06:02",
+ "custom": 0,
"description": "**Currency** Master",
"docstatus": 0,
"doctype": "DocType",
+ "document_type": "Setup",
"fields": [
{
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"fieldname": "currency_name",
"fieldtype": "Data",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
"label": "Currency Name",
+ "length": 0,
+ "no_copy": 0,
"oldfieldname": "currency_name",
"oldfieldtype": "Data",
"permlevel": 0,
- "reqd": 1
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
},
{
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"fieldname": "enabled",
"fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
"in_list_view": 1,
"label": "Enabled",
- "permlevel": 0
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
},
{
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"description": "Sub-currency. For e.g. \"Cent\"",
"fieldname": "fraction",
"fieldtype": "Data",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
"in_list_view": 1,
"label": "Fraction",
- "permlevel": 0
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
},
{
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"description": "1 Currency = [?] Fraction\nFor e.g. 1 USD = 100 Cent",
"fieldname": "fraction_units",
"fieldtype": "Int",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
"in_list_view": 1,
"label": "Fraction Units",
- "permlevel": 0
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
},
{
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"description": "A symbol for this currency. For e.g. $",
"fieldname": "symbol",
"fieldtype": "Data",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
"in_list_view": 1,
"label": "Symbol",
- "permlevel": 0
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
},
{
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"description": "How should this currency be formatted? If not set, will use system defaults",
"fieldname": "number_format",
"fieldtype": "Select",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
"in_list_view": 1,
"label": "Number Format",
+ "length": 0,
+ "no_copy": 0,
"options": "\n#,###.##\n#.###,##\n# ###.##\n# ###,##\n#'###.##\n#, ###.##\n#,##,###.##\n#,###.###\n#.###\n#,###",
- "permlevel": 0
+ "permlevel": 0,
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
}
],
+ "hide_heading": 0,
+ "hide_toolbar": 0,
"icon": "icon-bitcoin",
"idx": 1,
"in_create": 0,
- "modified": "2015-02-05 05:11:36.294972",
+ "in_dialog": 0,
+ "is_submittable": 0,
+ "issingle": 0,
+ "istable": 0,
+ "max_attachments": 0,
+ "modified": "2015-11-16 06:29:43.978225",
"modified_by": "Administrator",
"module": "Geo",
"name": "Currency",
@@ -66,28 +168,85 @@
"permissions": [
{
"amend": 0,
+ "apply_user_permissions": 0,
+ "cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
+ "export": 0,
+ "if_owner": 0,
+ "import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
+ "set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
},
{
- "apply_user_permissions": 1,
+ "amend": 0,
+ "apply_user_permissions": 0,
+ "cancel": 0,
+ "create": 0,
"delete": 0,
- "email": 1,
+ "email": 0,
+ "export": 0,
+ "if_owner": 0,
+ "import": 0,
"permlevel": 0,
- "print": 1,
+ "print": 0,
"read": 1,
- "report": 1,
- "role": "All"
+ "report": 0,
+ "role": "Accounts User",
+ "set_user_permissions": 0,
+ "share": 0,
+ "submit": 0,
+ "write": 0
+ },
+ {
+ "amend": 0,
+ "apply_user_permissions": 0,
+ "cancel": 0,
+ "create": 0,
+ "delete": 0,
+ "email": 0,
+ "export": 0,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 0,
+ "read": 1,
+ "report": 0,
+ "role": "Sales User",
+ "set_user_permissions": 0,
+ "share": 0,
+ "submit": 0,
+ "write": 0
+ },
+ {
+ "amend": 0,
+ "apply_user_permissions": 0,
+ "cancel": 0,
+ "create": 0,
+ "delete": 0,
+ "email": 0,
+ "export": 0,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 0,
+ "read": 1,
+ "report": 0,
+ "role": "Purchase User",
+ "set_user_permissions": 0,
+ "share": 0,
+ "submit": 0,
+ "write": 0
}
],
- "read_only": 0
+ "read_only": 0,
+ "read_only_onload": 0
}
\ No newline at end of file
diff --git a/frappe/handler.py b/frappe/handler.py
index 25e28a063d..43fdf71414 100755
--- a/frappe/handler.py
+++ b/frappe/handler.py
@@ -5,10 +5,12 @@ from __future__ import unicode_literals
import frappe
from frappe import _
import frappe.utils
+import frappe.async
import frappe.sessions
import frappe.utils.file_manager
import frappe.desk.form.run_method
from frappe.utils.response import build_response
+import bleach
@frappe.whitelist(allow_guest=True)
def version():
@@ -18,6 +20,10 @@ def version():
def ping():
return "pong"
+@frappe.async.handler
+def async_ping():
+ return "pong"
+
@frappe.whitelist()
def runserverobj(method, docs=None, dt=None, dn=None, arg=None, args=None):
frappe.desk.form.run_method.runserverobj(method, docs=docs, dt=dt, dn=dn, arg=arg, args=args)
@@ -54,7 +60,9 @@ def uploadfile():
frappe.db.rollback()
else:
if frappe.form_dict.get('method'):
- ret = frappe.get_attr(frappe.form_dict.method)()
+ method = frappe.get_attr(frappe.form_dict.method)
+ is_whitelisted(method)
+ ret = method()
except Exception:
frappe.errprint(frappe.utils.get_traceback())
ret = None
@@ -70,7 +78,7 @@ def handle():
return build_response("json")
-def execute_cmd(cmd):
+def execute_cmd(cmd, from_async=False):
"""execute a request as python module"""
for hook in frappe.get_hooks("override_whitelisted_methods", {}).get(cmd, []):
# override using the first hook
@@ -78,16 +86,10 @@ def execute_cmd(cmd):
break
method = get_attr(cmd)
+ if from_async:
+ method = method.queue
- # check if whitelisted
- if frappe.session['user'] == 'Guest':
- if (method not in frappe.guest_methods):
- frappe.msgprint(_("Not permitted"))
- raise frappe.PermissionError('Not Allowed, %s' % str(method))
- else:
- if not method in frappe.whitelisted:
- frappe.msgprint(_("Not permitted"))
- raise frappe.PermissionError('Not Allowed, %s' % str(method))
+ is_whitelisted(method)
ret = frappe.call(method, **frappe.form_dict)
@@ -95,6 +97,26 @@ def execute_cmd(cmd):
if ret:
frappe.response['message'] = ret
+def is_whitelisted(method):
+ # check if whitelisted
+ if frappe.session['user'] == 'Guest':
+ if (method not in frappe.guest_methods):
+ frappe.msgprint(_("Not permitted"))
+ raise frappe.PermissionError('Not Allowed, {0}'.format(method))
+
+ if method not in frappe.xss_safe_methods:
+ # strictly sanitize form_dict
+ # escapes html characters like <> except for predefined tags like a, b, ul etc.
+ # if required, we can add more whitelisted tags like div, p, etc. (see its documentation)
+ for key, value in frappe.form_dict.items():
+ if isinstance(value, basestring):
+ frappe.form_dict[key] = bleach.clean(value)
+
+ else:
+ if not method in frappe.whitelisted:
+ frappe.msgprint(_("Not permitted"))
+ raise frappe.PermissionError('Not Allowed, {0}'.format(method))
+
def get_attr(cmd):
"""get method object from cmd"""
if '.' in cmd:
@@ -103,3 +125,15 @@ def get_attr(cmd):
method = globals()[cmd]
frappe.log("method:" + cmd)
return method
+
+
+@frappe.whitelist()
+def get_async_task_status(task_id):
+ from frappe.celery_app import get_celery
+ c = get_celery()
+ a = c.AsyncResult(task_id)
+ frappe.local.response['response'] = a.result
+ return {
+ "state": a.state,
+ "progress": 0
+ }
diff --git a/frappe/hooks.py b/frappe/hooks.py
index 4211f2d6d8..76d975d919 100644
--- a/frappe/hooks.py
+++ b/frappe/hooks.py
@@ -2,12 +2,15 @@ from __future__ import unicode_literals
app_name = "frappe"
app_title = "Frappe Framework"
app_publisher = "Frappe Technologies Pvt. Ltd."
-app_description = "Full Stack Web Application Framework in Python"
-app_icon = "octicon octicon-circuit-board"
-app_version = "5.0.29"
-app_color = "orange"
+app_description = "Full stack web framework with Python, Javascript, MariaDB, Redis, Node"
-app_email = "support@frappe.io"
+app_icon = "octicon octicon-circuit-board"
+app_version = "6.16.4"
+app_color = "orange"
+source_link = "https://github.com/frappe/frappe"
+app_license = "MIT"
+
+app_email = "info@frappe.io"
before_install = "frappe.utils.install.before_install"
after_install = "frappe.utils.install.after_install"
@@ -35,8 +38,7 @@ web_include_js = [
bootstrap = "assets/frappe/css/bootstrap.css"
web_include_css = [
- "assets/css/frappe-web.css",
- "website_theme.css"
+ "assets/css/frappe-web.css"
]
website_route_rules = [
{"from_route": "/blog", "to_route": "Blog Post"},
@@ -59,6 +61,8 @@ website_generators = ["Web Page", "Blog Post", "Blog Category", "Web Form"]
email_append_to = ["Event", "ToDo", "Communication"]
+calendars = ["Event"]
+
# login
on_session_creation = [
@@ -115,6 +119,7 @@ scheduler_events = {
"frappe.email.bulk.flush",
"frappe.email.doctype.email_account.email_account.pull",
"frappe.email.doctype.email_account.email_account.notify_unreplied",
+ "frappe.utils.error.collect_error_snapshots",
],
"daily": [
"frappe.email.bulk.clear_outbox",
@@ -123,11 +128,31 @@ scheduler_events = {
"frappe.desk.doctype.event.event.send_event_digest",
"frappe.sessions.clear_expired_sessions",
"frappe.email.doctype.email_alert.email_alert.trigger_daily_alerts",
+ "frappe.async.remove_old_task_logs",
+ ],
+ "daily_long": [
+ "frappe.integrations.doctype.dropbox_backup.dropbox_backup.take_backups_daily"
+ ],
+ "weekly_long": [
+ "frappe.integrations.doctype.dropbox_backup.dropbox_backup.take_backups_weekly"
]
+
}
default_background = "/assets/frappe/images/ui/into-the-dawn.jpg"
get_translated_dict = {
- ("doctype", "System Settings"): "frappe.geo.country_info.get_translated_dict"
+ ("doctype", "System Settings"): "frappe.geo.country_info.get_translated_dict",
+ ("page", "setup-wizard"): "frappe.geo.country_info.get_translated_dict"
}
+
+sounds = [
+ {"name": "email", "src": "/assets/frappe/sounds/email.mp3"},
+ {"name": "submit", "src": "/assets/frappe/sounds/submit.mp3"},
+ {"name": "cancel", "src": "/assets/frappe/sounds/cancel.mp3"},
+ {"name": "delete", "src": "/assets/frappe/sounds/delete.mp3"},
+ {"name": "click", "src": "/assets/frappe/sounds/click.mp3"},
+ {"name": "error", "src": "/assets/frappe/sounds/error.mp3"},
+ # {"name": "alert", "src": "/assets/frappe/sounds/alert.mp3"},
+ # {"name": "chime", "src": "/assets/frappe/sounds/chime.mp3"},
+]
diff --git a/frappe/installer.py b/frappe/installer.py
index 4c3c10e538..32defc6e3e 100755
--- a/frappe/installer.py
+++ b/frappe/installer.py
@@ -98,7 +98,6 @@ def install_app(name, verbose=False, set_as_patched=True):
for app in app_hooks.required_apps:
install_app(app)
- print "Installing {0}...".format(name)
frappe.flags.in_install = name
frappe.clear_cache()
@@ -106,15 +105,18 @@ def install_app(name, verbose=False, set_as_patched=True):
raise Exception("App not in apps.txt")
if name in installed_apps:
- print "Already installed"
frappe.msgprint("App {0} already installed".format(name))
return
+ print "Installing {0}...".format(name)
+
if name != "frappe":
frappe.only_for("System Manager")
for before_install in app_hooks.before_install or []:
- frappe.get_attr(before_install)()
+ out = frappe.get_attr(before_install)()
+ if out==False:
+ return
if name != "frappe":
add_module_defs(name)
@@ -151,6 +153,36 @@ def remove_from_installed_apps(app_name):
if frappe.flags.in_install:
post_install()
+def remove_app(app_name, dry_run=False):
+ """Delete app and all linked to the app's module with the app."""
+
+ if not dry_run:
+ confirm = raw_input("All doctypes (including custom), modules related to this app will be deleted. Are you sure you want to continue (y/n) ? ")
+ if confirm!="y":
+ return
+
+ from frappe.utils.backups import scheduled_backup
+ print "Backing up..."
+ scheduled_backup(ignore_files=True)
+
+ # remove modules, doctypes, roles
+ for module_name in frappe.get_module_list(app_name):
+ for doctype in frappe.get_list("DocType", filters={"module": module_name},
+ fields=["name", "issingle"]):
+ print "removing {0}...".format(doctype.name)
+ # drop table
+
+ if not dry_run:
+ if not doctype.issingle:
+ frappe.db.sql("drop table `tab{0}`".format(doctype.name))
+ frappe.delete_doc("DocType", doctype.name)
+
+ print "removing Module {0}...".format(module_name)
+ if not dry_run:
+ frappe.delete_doc("Module Def", module_name)
+
+ remove_from_installed_apps(app_name)
+
def post_install(rebuild_website=False):
if rebuild_website:
render.clear_cache()
@@ -167,7 +199,7 @@ def set_all_patches_as_completed(app):
frappe.get_doc({
"doctype": "Patch Log",
"patch": patch
- }).insert()
+ }).insert(ignore_permissions=True)
frappe.db.commit()
def init_singles():
@@ -188,7 +220,7 @@ def make_conf(db_name=None, db_password=None, site_config=None):
def make_site_config(db_name=None, db_password=None, site_config=None):
frappe.create_folder(os.path.join(frappe.local.site_path))
- site_file = os.path.join(frappe.local.site_path, "site_config.json")
+ site_file = get_site_config_path()
if not os.path.exists(site_file):
if not (site_config and isinstance(site_config, dict)):
@@ -197,6 +229,34 @@ def make_site_config(db_name=None, db_password=None, site_config=None):
with open(site_file, "w") as f:
f.write(json.dumps(site_config, indent=1, sort_keys=True))
+def update_site_config(key, value):
+ """Update a value in site_config"""
+ with open(get_site_config_path(), "r") as f:
+ site_config = json.loads(f.read())
+
+ # int
+ try:
+ value = int(value)
+ except ValueError:
+ pass
+
+ # boolean
+ if value in ("False", "True"):
+ value = eval(value)
+
+ # remove key if value is None
+ if value == "None":
+ if key in site_config:
+ del site_config[key]
+ else:
+ site_config[key] = value
+
+ with open(get_site_config_path(), "w") as f:
+ f.write(json.dumps(site_config, indent=1, sort_keys=True))
+
+def get_site_config_path():
+ return os.path.join(frappe.local.site_path, "site_config.json")
+
def get_conf_params(db_name=None, db_password=None):
if not db_name:
db_name = raw_input("Database Name: ")
@@ -214,7 +274,9 @@ def make_site_dirs():
site_private_path = os.path.join(frappe.local.site_path, 'private')
for dir_path in (
os.path.join(site_private_path, 'backups'),
- os.path.join(site_public_path, 'files')):
+ os.path.join(site_public_path, 'files'),
+ os.path.join(site_private_path, 'files'),
+ os.path.join(frappe.local.site_path, 'task-logs')):
if not os.path.exists(dir_path):
os.makedirs(dir_path)
locks_dir = frappe.get_site_path('locks')
@@ -227,7 +289,7 @@ def add_module_defs(app):
d = frappe.new_doc("Module Def")
d.app_name = app
d.module_name = module
- d.save()
+ d.save(ignore_permissions=True)
def remove_missing_apps():
apps = ('frappe_subscription', 'shopping_cart')
diff --git a/frappe/integrations/__init__.py b/frappe/integrations/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/frappe/integrations/doctype/__init__.py b/frappe/integrations/doctype/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/frappe/integrations/doctype/dropbox_backup/__init__.py b/frappe/integrations/doctype/dropbox_backup/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/frappe/integrations/doctype/dropbox_backup/dropbox_backup.js b/frappe/integrations/doctype/dropbox_backup/dropbox_backup.js
new file mode 100644
index 0000000000..99d39949e6
--- /dev/null
+++ b/frappe/integrations/doctype/dropbox_backup/dropbox_backup.js
@@ -0,0 +1,37 @@
+$.extend(cur_frm.cscript, {
+ onload_post_render: function() {
+ cur_frm.fields_dict.allow_dropbox_access.$input.addClass("btn-primary");
+ },
+
+ refresh: function() {
+ cur_frm.disable_save();
+ },
+
+ validate_send_notifications_to: function() {
+ if(!cur_frm.doc.send_notifications_to) {
+ msgprint(__("Please specify") + ": " +
+ __(frappe.meta.get_label(cur_frm.doctype,
+ "send_notifications_to")));
+ return false;
+ }
+
+ return true;
+ },
+
+ allow_dropbox_access: function() {
+ if(cur_frm.cscript.validate_send_notifications_to()) {
+ return frappe.call({
+ method: "frappe.integrations.doctype.dropbox_backup.dropbox_backup.get_dropbox_authorize_url",
+ callback: function(r) {
+ if(!r.exc) {
+ cur_frm.set_value("dropbox_access_secret", r.message.secret);
+ cur_frm.set_value("dropbox_access_key", r.message.key);
+ cur_frm.save(null, function() {
+ window.open(r.message.url);
+ });
+ }
+ }
+ });
+ }
+ }
+});
diff --git a/frappe/integrations/doctype/dropbox_backup/dropbox_backup.json b/frappe/integrations/doctype/dropbox_backup/dropbox_backup.json
new file mode 100644
index 0000000000..938201cdf1
--- /dev/null
+++ b/frappe/integrations/doctype/dropbox_backup/dropbox_backup.json
@@ -0,0 +1,210 @@
+{
+ "allow_copy": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "creation": "2015-09-24 01:16:21.711868",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "Setup",
+ "fields": [
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "fieldname": "send_backups_to_dropbox",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Send Backups to Dropbox",
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "default": "Daily",
+ "depends_on": "send_backups_to_dropbox",
+ "fieldname": "upload_backups_to_dropbox",
+ "fieldtype": "Select",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Upload Frequency",
+ "no_copy": 0,
+ "options": "Daily\nWeekly",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "depends_on": "send_backups_to_dropbox",
+ "fieldname": "send_notifications_to",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Send Notifications To",
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "fieldname": "dropbox_access_key",
+ "fieldtype": "Data",
+ "hidden": 1,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Dropbox Access Key",
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "fieldname": "dropbox_access_secret",
+ "fieldtype": "Data",
+ "hidden": 1,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Dropbox Access Secret",
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "fieldname": "dropbox_access_allowed",
+ "fieldtype": "Data",
+ "hidden": 1,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Dropbox Access Allowed",
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "depends_on": "send_backups_to_dropbox",
+ "fieldname": "allow_dropbox_access",
+ "fieldtype": "Button",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Allow Dropbox Access",
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ }
+ ],
+ "hide_heading": 0,
+ "hide_toolbar": 0,
+ "in_create": 0,
+ "in_dialog": 0,
+ "is_submittable": 0,
+ "issingle": 1,
+ "istable": 0,
+ "modified": "2015-09-24 01:42:25.670481",
+ "modified_by": "Administrator",
+ "module": "Integrations",
+ "name": "Dropbox Backup",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "amend": 0,
+ "apply_user_permissions": 0,
+ "cancel": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 0,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 0,
+ "role": "System Manager",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
+ "write": 1
+ }
+ ],
+ "read_only": 0,
+ "read_only_onload": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC"
+}
\ No newline at end of file
diff --git a/frappe/integrations/doctype/dropbox_backup/dropbox_backup.py b/frappe/integrations/doctype/dropbox_backup/dropbox_backup.py
new file mode 100644
index 0000000000..6571955a6d
--- /dev/null
+++ b/frappe/integrations/doctype/dropbox_backup/dropbox_backup.py
@@ -0,0 +1,225 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+# SETUP:
+# install pip install --upgrade dropbox
+#
+# Create new Dropbox App
+#
+# in conf.py, set oauth2 settings
+# dropbox_access_key
+# dropbox_access_secret
+
+from __future__ import unicode_literals
+import frappe
+from frappe.model.document import Document
+from frappe.utils import cint, split_emails, get_request_site_address, cstr
+import os
+from frappe import _
+
+ignore_list = [".DS_Store"]
+
+class DropboxBackup(Document):
+ pass
+
+def take_backups_daily():
+ take_backups_if("Daily")
+
+def take_backups_weekly():
+ take_backups_if("Weekly")
+
+def take_backups_if(freq):
+ if cint(frappe.db.get_value("Dropbox Backup", None, "send_backups_to_dropbox")):
+ if frappe.db.get_value("Dropbox Backup", None, "upload_backups_to_dropbox")==freq:
+ take_backups_dropbox()
+
+@frappe.whitelist()
+def take_backups_dropbox():
+ did_not_upload, error_log = [], []
+ try:
+ from frappe.integrations.doctype.dropbox_backup.dropbox_backup import backup_to_dropbox
+ did_not_upload, error_log = backup_to_dropbox()
+ if did_not_upload: raise Exception
+
+ send_email(True, "Dropbox")
+ except Exception:
+ file_and_error = [" - ".join(f) for f in zip(did_not_upload, error_log)]
+ error_message = ("\n".join(file_and_error) + "\n" + frappe.get_traceback())
+ frappe.errprint(error_message)
+ send_email(False, "Dropbox", error_message)
+
+def send_email(success, service_name, error_status=None):
+ if success:
+ subject = "Backup Upload Successful"
+ message ="""Backup Uploaded Successfully Hi there, this is just to inform you
+ that your backup was successfully uploaded to your %s account. So relax!
+ """ % service_name
+
+ else:
+ subject = "[Warning] Backup Upload Failed"
+ message ="""Backup Upload Failed Oops, your automated backup to %s
+ failed.
+ Error message: %s
+ Please contact your system manager for more information.
+ """ % (service_name, error_status)
+
+ if not frappe.db:
+ frappe.connect()
+
+ recipients = split_emails(frappe.db.get_value("Dropbox Backup", None, "send_notifications_to"))
+ frappe.sendmail(recipients=recipients, subject=subject, message=message)
+
+@frappe.whitelist()
+def get_dropbox_authorize_url():
+ sess = get_dropbox_session()
+ request_token = sess.obtain_request_token()
+ return_address = get_request_site_address(True) \
+ + "?cmd=frappe.integrations.doctype.dropbox_backup.dropbox_backup.dropbox_callback"
+
+ url = sess.build_authorize_url(request_token, return_address)
+
+ return {
+ "url": url,
+ "key": request_token.key,
+ "secret": request_token.secret,
+ }
+
+@frappe.whitelist(allow_guest=True)
+def dropbox_callback(oauth_token=None, not_approved=False):
+ from dropbox import client
+ if not not_approved:
+ if frappe.db.get_value("Dropbox Backup", None, "dropbox_access_key")==oauth_token:
+ allowed = 1
+ message = "Dropbox access allowed."
+
+ sess = get_dropbox_session()
+ sess.set_request_token(frappe.db.get_value("Dropbox Backup", None, "dropbox_access_key"),
+ frappe.db.get_value("Dropbox Backup", None, "dropbox_access_secret"))
+ access_token = sess.obtain_access_token()
+ frappe.db.set_value("Dropbox Backup", "Dropbox Backup", "dropbox_access_key", access_token.key)
+ frappe.db.set_value("Dropbox Backup", "Dropbox Backup", "dropbox_access_secret", access_token.secret)
+ frappe.db.set_value("Dropbox Backup", "Dropbox Backup", "dropbox_access_allowed", allowed)
+ frappe.db.set_value("Dropbox Backup", "Dropbox Backup", "send_backups_to_dropbox", 1)
+ dropbox_client = client.DropboxClient(sess)
+ # try:
+ # dropbox_client.file_create_folder("private")
+ # dropbox_client.file_create_folder("private/files")
+ # dropbox_client.file_create_folder("files")
+ # except:
+ # pass
+
+ else:
+ allowed = 0
+ message = "Illegal Access Token Please try again."
+ else:
+ allowed = 0
+ message = "Dropbox Access not approved."
+
+ frappe.local.message_title = "Dropbox Approval"
+ frappe.local.message = "%s Please close this window.
" % message
+
+ if allowed:
+ frappe.local.message_success = True
+
+ frappe.db.commit()
+ frappe.response['type'] = 'page'
+ frappe.response['page_name'] = 'message.html'
+
+def backup_to_dropbox():
+ from dropbox import client, session
+ from frappe.utils.backups import new_backup
+ from frappe.utils import get_files_path, get_backups_path
+ if not frappe.db:
+ frappe.connect()
+
+ sess = session.DropboxSession(frappe.conf.dropbox_access_key, frappe.conf.dropbox_secret_key, "app_folder")
+
+ sess.set_token(frappe.db.get_value("Dropbox Backup", None, "dropbox_access_key"),
+ frappe.db.get_value("Dropbox Backup", None, "dropbox_access_secret"))
+
+ dropbox_client = client.DropboxClient(sess)
+
+ # upload database
+ backup = new_backup(ignore_files=True)
+ filename = os.path.join(get_backups_path(), os.path.basename(backup.backup_path_db))
+ upload_file_to_dropbox(filename, "/database", dropbox_client)
+
+ frappe.db.close()
+
+ # upload files to files folder
+ did_not_upload = []
+ error_log = []
+
+ upload_from_folder(get_files_path(), "/files", dropbox_client, did_not_upload, error_log)
+ upload_from_folder(get_files_path(is_private=1), "/private/files", dropbox_client, did_not_upload, error_log)
+
+ frappe.connect()
+ return did_not_upload, list(set(error_log))
+
+def upload_from_folder(path, dropbox_folder, dropbox_client, did_not_upload, error_log):
+ import dropbox.rest
+
+ if not os.path.exists(path):
+ return
+
+ try:
+ response = dropbox_client.metadata(dropbox_folder)
+ except dropbox.rest.ErrorResponse, e:
+ # folder not found
+ if e.status==404:
+ response = {"contents": []}
+
+ for filename in os.listdir(path):
+ filename = cstr(filename)
+
+ if filename in ignore_list:
+ continue
+
+ found = False
+ filepath = os.path.join(path, filename)
+ for file_metadata in response["contents"]:
+ if os.path.basename(filepath) == os.path.basename(file_metadata["path"]) and os.stat(filepath).st_size == int(file_metadata["bytes"]):
+ found = True
+ break
+
+ if not found:
+ try:
+ upload_file_to_dropbox(filepath, dropbox_folder, dropbox_client)
+ except Exception:
+ did_not_upload.append(filename)
+ error_log.append(frappe.get_traceback())
+
+def get_dropbox_session():
+ try:
+ from dropbox import session
+ except:
+ frappe.msgprint(_("Please install dropbox python module"), raise_exception=1)
+
+ if not (frappe.conf.dropbox_access_key or frappe.conf.dropbox_secret_key):
+ frappe.throw(_("Please set Dropbox access keys in your site config"))
+
+ sess = session.DropboxSession(frappe.conf.dropbox_access_key, frappe.conf.dropbox_secret_key, "app_folder")
+ return sess
+
+def upload_file_to_dropbox(filename, folder, dropbox_client):
+ from dropbox import rest
+ size = os.stat(filename).st_size
+
+ with open(filename, 'r') as f:
+ # if max packet size reached, use chunked uploader
+ max_packet_size = 4194304
+
+ if size > max_packet_size:
+ uploader = dropbox_client.get_chunked_uploader(f, size)
+ while uploader.offset < size:
+ try:
+ uploader.upload_chunked()
+ uploader.finish(folder + "/" + os.path.basename(filename), overwrite=True)
+ except rest.ErrorResponse:
+ pass
+ else:
+ dropbox_client.put_file(folder + "/" + os.path.basename(filename), f, overwrite=True)
+
+if __name__=="__main__":
+ backup_to_dropbox()
diff --git a/frappe/integrations/doctype/social_login_keys/__init__.py b/frappe/integrations/doctype/social_login_keys/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/frappe/integrations/doctype/social_login_keys/social_login_keys.json b/frappe/integrations/doctype/social_login_keys/social_login_keys.json
new file mode 100644
index 0000000000..fdb469c65c
--- /dev/null
+++ b/frappe/integrations/doctype/social_login_keys/social_login_keys.json
@@ -0,0 +1,239 @@
+{
+ "allow_copy": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "creation": "2014-03-04 08:29:52",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "System",
+ "fields": [
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "fieldname": "facebook",
+ "fieldtype": "Section Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Facebook",
+ "no_copy": 0,
+ "permlevel": 0,
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "fieldname": "facebook_client_id",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Facebook Client ID",
+ "no_copy": 0,
+ "permlevel": 0,
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "fieldname": "facebook_client_secret",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Facebook Client Secret",
+ "no_copy": 0,
+ "permlevel": 0,
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "fieldname": "google",
+ "fieldtype": "Section Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Google",
+ "no_copy": 0,
+ "permlevel": 0,
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "fieldname": "google_client_id",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Google Client ID",
+ "no_copy": 0,
+ "permlevel": 0,
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "fieldname": "google_client_secret",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Google Client Secret",
+ "no_copy": 0,
+ "permlevel": 0,
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "fieldname": "github",
+ "fieldtype": "Section Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "GitHub",
+ "no_copy": 0,
+ "permlevel": 0,
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "fieldname": "github_client_id",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "GitHub Client ID",
+ "no_copy": 0,
+ "permlevel": 0,
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "fieldname": "github_client_secret",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "GitHub Client Secret",
+ "no_copy": 0,
+ "permlevel": 0,
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ }
+ ],
+ "hide_heading": 0,
+ "hide_toolbar": 0,
+ "icon": "icon-signin",
+ "idx": 1,
+ "in_create": 0,
+ "in_dialog": 0,
+ "is_submittable": 0,
+ "issingle": 1,
+ "istable": 0,
+ "modified": "2015-08-05 08:14:52.667728",
+ "modified_by": "Administrator",
+ "module": "Integrations",
+ "name": "Social Login Keys",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "amend": 0,
+ "apply_user_permissions": 0,
+ "cancel": 0,
+ "create": 1,
+ "delete": 0,
+ "email": 0,
+ "export": 0,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 0,
+ "read": 1,
+ "report": 0,
+ "role": "System Manager",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
+ "write": 1
+ }
+ ],
+ "read_only": 0,
+ "read_only_onload": 0
+}
\ No newline at end of file
diff --git a/frappe/website/doctype/social_login_keys/social_login_keys.py b/frappe/integrations/doctype/social_login_keys/social_login_keys.py
similarity index 100%
rename from frappe/website/doctype/social_login_keys/social_login_keys.py
rename to frappe/integrations/doctype/social_login_keys/social_login_keys.py
diff --git a/frappe/model/__init__.py b/frappe/model/__init__.py
index ab3630ec59..0560043894 100644
--- a/frappe/model/__init__.py
+++ b/frappe/model/__init__.py
@@ -72,111 +72,3 @@ def delete_fields(args_dict, delete=0):
", ".join(["DROP COLUMN `%s`" % f for f in fields if f in existing_fields])
frappe.db.commit()
frappe.db.sql(query)
-
-def rename_field(doctype, old_fieldname, new_fieldname):
- """This functions assumes that doctype is already synced"""
-
- meta = frappe.get_meta(doctype, cached=False)
- new_field = meta.get_field(new_fieldname)
- if not new_field:
- print "rename_field: " + (new_fieldname) + " not found in " + doctype
- return
-
- if new_field.fieldtype == "Table":
- # change parentfield of table mentioned in options
- frappe.db.sql("""update `tab%s` set parentfield=%s
- where parentfield=%s""" % (new_field.options.split("\n")[0], "%s", "%s"),
- (new_fieldname, old_fieldname))
- elif new_field.fieldtype not in no_value_fields:
- if meta.issingle:
- frappe.db.sql("""update `tabSingles` set field=%s
- where doctype=%s and field=%s""",
- (new_fieldname, doctype, old_fieldname))
- else:
- # copy field value
- frappe.db.sql("""update `tab%s` set `%s`=`%s`""" % \
- (doctype, new_fieldname, old_fieldname))
-
- update_reports(doctype, old_fieldname, new_fieldname)
- update_users_report_view_settings(doctype, old_fieldname, new_fieldname)
-
- # update in property setter
- frappe.db.sql("""update `tabProperty Setter` set field_name = %s
- where doc_type=%s and field_name=%s""", (new_fieldname, doctype, old_fieldname))
-
-def update_reports(doctype, old_fieldname, new_fieldname):
- def _get_new_sort_by(report_dict, report, key):
- sort_by = report_dict.get(key) or ""
- if sort_by:
- sort_by = sort_by.split(".")
- if len(sort_by) > 1:
- if sort_by[0]==doctype and sort_by[1]==old_fieldname:
- sort_by = doctype + "." + new_fieldname
- report_dict["updated"] = True
- elif report.ref_doctype == doctype and sort_by[0]==old_fieldname:
- sort_by = doctype + "." + new_fieldname
- report_dict["updated"] = True
-
- if isinstance(sort_by, list):
- sort_by = '.'.join(sort_by)
-
- return sort_by
-
- reports = frappe.db.sql("""select name, ref_doctype, json from tabReport
- where report_type = 'Report Builder' and ifnull(is_standard, 'No') = 'No'
- and json like %s and json like %s""",
- ('%%%s%%' % old_fieldname , '%%%s%%' % doctype), as_dict=True)
-
- for r in reports:
- report_dict = json.loads(r.json)
-
- # update filters
- new_filters = []
- for f in report_dict.get("filters"):
- if f and len(f) > 1 and f[0] == doctype and f[1] == old_fieldname:
- new_filters.append([doctype, new_fieldname, f[2], f[3]])
- report_dict["updated"] = True
- else:
- new_filters.append(f)
-
- # update columns
- new_columns = []
- for c in report_dict.get("columns"):
- if c and len(c) > 1 and c[0] == old_fieldname and c[1] == doctype:
- new_columns.append([new_fieldname, doctype])
- report_dict["updated"] = True
- else:
- new_columns.append(c)
-
- # update sort by
- new_sort_by = _get_new_sort_by(report_dict, r, "sort_by")
- new_sort_by_next = _get_new_sort_by(report_dict, r, "sort_by_next")
-
- if report_dict.get("updated"):
- new_val = json.dumps({
- "filters": new_filters,
- "columns": new_columns,
- "sort_by": new_sort_by,
- "sort_order": report_dict.get("sort_order"),
- "sort_by_next": new_sort_by_next,
- "sort_order_next": report_dict.get("sort_order_next")
- })
-
- frappe.db.sql("""update `tabReport` set `json`=%s where name=%s""", (new_val, r.name))
-
-def update_users_report_view_settings(doctype, ref_fieldname, new_fieldname):
- user_report_cols = frappe.db.sql("""select defkey, defvalue from `tabDefaultValue` where
- defkey like '_list_settings:%'""")
- for key, value in user_report_cols:
- new_columns = []
- columns_modified = False
- for field, field_doctype in json.loads(value):
- if field == ref_fieldname and field_doctype == doctype:
- new_columns.append([new_fieldname, field_doctype])
- columns_modified=True
- else:
- new_columns.append([field, field_doctype])
-
- if columns_modified:
- frappe.db.sql("""update `tabDefaultValue` set defvalue=%s
- where defkey=%s""" % ('%s', '%s'), (json.dumps(new_columns), key))
diff --git a/frappe/model/base_document.py b/frappe/model/base_document.py
index 1b1116e55b..ab33d4b8c3 100644
--- a/frappe/model/base_document.py
+++ b/frappe/model/base_document.py
@@ -9,6 +9,7 @@ from frappe.model import default_fields
from frappe.model.naming import set_new_name
from frappe.modules import load_doctype_module
from frappe.model import display_fieldtypes
+from frappe.model.db_schema import type_map, varchar_len
_classes = {}
@@ -161,6 +162,9 @@ class BaseDocument(object):
value.parenttype = self.doctype
value.parentfield = key
+ if value.docstatus is None:
+ value.docstatus = 0
+
if not getattr(value, "idx", None):
value.idx = len(self.get(key) or []) + 1
@@ -174,9 +178,19 @@ class BaseDocument(object):
for fieldname in self.meta.get_valid_columns():
d[fieldname] = self.get(fieldname)
- if d[fieldname]=="":
- df = self.meta.get_field(fieldname)
- if df and df.fieldtype in ("Datetime", "Date"):
+ df = self.meta.get_field(fieldname)
+ if df:
+ if df.fieldtype in ("Check", "Int") and not isinstance(d[fieldname], int):
+ d[fieldname] = cint(d[fieldname])
+
+ elif df.fieldtype in ("Currency", "Float", "Percent") and not isinstance(d[fieldname], float):
+ d[fieldname] = flt(d[fieldname])
+
+ elif df.fieldtype in ("Datetime", "Date") and d[fieldname]=="":
+ d[fieldname] = None
+
+ elif df.get("unique") and cstr(d[fieldname]).strip()=="":
+ # unique empty field should be set to None
d[fieldname] = None
return d
@@ -186,6 +200,9 @@ class BaseDocument(object):
if key not in self.__dict__:
self.__dict__[key] = None
+ if key in ("idx", "docstatus") and self.__dict__[key] is None:
+ self.__dict__[key] = 0
+
for key in self.get_valid_columns():
if key not in self.__dict__:
self.__dict__[key] = None
@@ -222,7 +239,7 @@ class BaseDocument(object):
if k in default_fields:
del doc[k]
- for key in ("_user_tags", "__islocal", "__onload", "_starred_by"):
+ for key in ("_user_tags", "__islocal", "__onload", "_starred_by", "__run_link_triggers"):
if self.get(key):
doc[key] = self.get(key)
@@ -253,15 +270,23 @@ class BaseDocument(object):
values = ", ".join(["%s"] * len(columns))
), d.values())
except Exception, e:
- if e.args[0]==1062 and "PRIMARY" in cstr(e.args[1]):
- if self.meta.autoname=="hash":
- # hash collision? try again
- self.name = None
- self.db_insert()
- return
- type, value, traceback = sys.exc_info()
- frappe.msgprint(_("Duplicate name {0} {1}").format(self.doctype, self.name))
- raise frappe.NameError, (self.doctype, self.name, e), traceback
+ if e.args[0]==1062:
+ if "PRIMARY" in cstr(e.args[1]):
+ if self.meta.autoname=="hash":
+ # hash collision? try again
+ self.name = None
+ self.db_insert()
+ return
+
+ type, value, traceback = sys.exc_info()
+ frappe.msgprint(_("Duplicate name {0} {1}").format(self.doctype, self.name))
+ raise frappe.DuplicateEntryError, (self.doctype, self.name, e), traceback
+
+ elif "Duplicate" in cstr(e.args[1]):
+ # unique constraint
+ self.show_unique_validation_message(e)
+ else:
+ raise
else:
raise
@@ -281,18 +306,35 @@ class BaseDocument(object):
values = ", ".join(["`"+c+"`=%s" for c in columns])
), d.values() + [d.get("name")])
except Exception, e:
- if e.args[0]==1062:
- type, value, traceback = sys.exc_info()
- fieldname = str(e).split("'")[-2]
- frappe.msgprint(_("{0} must be unique".format(self.meta.get_label(fieldname))))
- raise frappe.ValidationError, (self.doctype, self.name, e), traceback
+ if e.args[0]==1062 and "Duplicate" in cstr(e.args[1]):
+ self.show_unique_validation_message(e)
else:
raise
+ def show_unique_validation_message(self, e):
+ type, value, traceback = sys.exc_info()
+ fieldname, label = str(e).split("'")[-2], None
+
+ # unique_first_fieldname_second_fieldname is the constraint name
+ # created using frappe.db.add_unique
+ if "unique_" in fieldname:
+ fieldname = fieldname.split("_", 1)[1]
+
+ df = self.meta.get_field(fieldname)
+ if df:
+ label = df.label
+
+ frappe.msgprint(_("{0} must be unique".format(label or fieldname)))
+
+ # this is used to preserve traceback
+ raise frappe.UniqueValidationError, (self.doctype, self.name, e), traceback
+
def db_set(self, fieldname, value, update_modified=True):
self.set(fieldname, value)
- self.set("modified", now())
- self.set("modified_by", frappe.session.user)
+ if update_modified:
+ self.set("modified", now())
+ self.set("modified_by", frappe.session.user)
+
frappe.db.set_value(self.doctype, self.name, fieldname, value,
self.modified, self.modified_by, update_modified=update_modified)
@@ -411,13 +453,42 @@ class BaseDocument(object):
frappe.throw(_("Value cannot be changed for {0}").format(self.meta.get_label(fieldname)),
frappe.CannotChangeConstantError)
+ def _validate_length(self):
+ if frappe.flags.in_install:
+ return
+
+ for fieldname, value in self.get_valid_dict().iteritems():
+ df = self.meta.get_field(fieldname)
+ if df and df.fieldtype in type_map and type_map[df.fieldtype][0]=="varchar":
+ max_length = cint(df.get("length")) or cint(varchar_len)
+
+ if len(cstr(value)) > max_length:
+ if self.parentfield and self.idx:
+ reference = _("{0}, Row {1}").format(_(self.doctype), self.idx)
+
+ else:
+ reference = "{0} {1}".format(_(self.doctype), self.name)
+
+ frappe.throw(_("{0}: '{1}' will get truncated, as max characters allowed is {2}")\
+ .format(reference, _(df.label), max_length), frappe.CharacterLengthExceededError)
+
def _validate_update_after_submit(self):
- db_values = frappe.db.get_value(self.doctype, self.name, "*", as_dict=True)
- for key, db_value in db_values.iteritems():
+ # get the full doc with children
+ db_values = frappe.get_doc(self.doctype, self.name).as_dict()
+
+ for key in self.as_dict():
df = self.meta.get_field(key)
+ db_value = db_values.get(key)
if df and not df.allow_on_submit and (self.get(key) or db_value):
- self_value = self.get_value(key)
+ if df.fieldtype=="Table":
+ # just check if the table size has changed
+ # individual fields will be checked in the loop for children
+ self_value = len(self.get(key))
+ db_value = len(db_value)
+
+ else:
+ self_value = self.get_value(key)
if self_value != db_value:
frappe.throw(_("Not allowed to change {0} after submission").format(df.label),
@@ -453,7 +524,7 @@ class BaseDocument(object):
return self._precision[cache_key][fieldname]
- def get_formatted(self, fieldname, doc=None, currency=None):
+ def get_formatted(self, fieldname, doc=None, currency=None, absolute_value=False):
from frappe.utils.formatters import format_value
df = self.meta.get_field(fieldname)
@@ -461,7 +532,14 @@ class BaseDocument(object):
from frappe.model.meta import get_default_df
df = get_default_df(fieldname)
- return format_value(self.get(fieldname), df=df, doc=doc or self, currency=currency)
+ val = self.get(fieldname)
+ if absolute_value and isinstance(val, (int, float)):
+ val = abs(self.get(fieldname))
+
+ if not doc:
+ doc = getattr(self, "parent_doc", None) or self
+
+ return format_value(val, df=df, doc=doc, currency=currency)
def is_print_hide(self, fieldname, df=None, for_print=True):
"""Returns true if fieldname is to be hidden for print.
@@ -478,10 +556,16 @@ class BaseDocument(object):
meta_df = self.meta.get_field(fieldname)
if meta_df and meta_df.get("__print_hide"):
return True
- if df:
- return df.print_hide
- if meta_df:
- return meta_df.print_hide
+
+ print_hide = 0
+
+ if self.get(fieldname)==0 and not self.meta.istable:
+ print_hide = ( df and df.print_hide_if_no_value ) or ( meta_df and meta_df.print_hide_if_no_value )
+
+ if not print_hide:
+ print_hide = ( df and df.print_hide ) or ( meta_df and meta_df.print_hide )
+
+ return print_hide
def in_format_data(self, fieldname):
"""Returns True if shown via Print Format::`format_data` property.
diff --git a/frappe/model/create_new.py b/frappe/model/create_new.py
index a57b480288..464a9bc4c0 100644
--- a/frappe/model/create_new.py
+++ b/frappe/model/create_new.py
@@ -57,15 +57,19 @@ def set_user_and_static_default_values(doc):
doc.set(df.fieldname, user_default_value)
else:
- static_default_value = get_static_default_value(df, user_permissions)
- if static_default_value is not None:
- doc.set(df.fieldname, static_default_value)
+ if df.fieldname != doc.meta.title_field:
+ static_default_value = get_static_default_value(df, user_permissions)
+ if static_default_value is not None:
+ doc.set(df.fieldname, static_default_value)
def get_user_default_value(df, defaults, user_permissions):
# don't set defaults for "User" link field using User Permissions!
if df.fieldtype == "Link" and df.options != "User":
- # 1 - look in user permissions
- if user_permissions_exist(df, user_permissions) and len(user_permissions[df.options])==1:
+ # 1 - look in user permissions only for document_type==Setup
+ # We don't want to include permissions of transactions to be used for defaults.
+ if (frappe.get_meta(df.options).document_type=="Setup"
+ and user_permissions_exist(df, user_permissions)
+ and len(user_permissions[df.options])==1):
return user_permissions[df.options][0]
# 2 - Look in user defaults
@@ -105,7 +109,7 @@ def set_dynamic_default_values(doc, parent_doc, parentfield):
if df.get("default"):
if df.default.startswith(":"):
default_value = get_default_based_on_another_field(df, user_permissions, parent_doc)
- if default_value is not None:
+ if default_value is not None and not doc.get(df.fieldname):
doc[df.fieldname] = default_value
elif df.fieldtype == "Datetime" and df.default.lower() == "now":
diff --git a/frappe/model/db_query.py b/frappe/model/db_query.py
index ee1166be87..e69758396a 100644
--- a/frappe/model/db_query.py
+++ b/frappe/model/db_query.py
@@ -201,56 +201,87 @@ class DatabaseQuery(object):
"""build conditions from user filters"""
if isinstance(filters, dict):
filters = [filters]
+
for f in filters:
if isinstance(f, basestring):
conditions.append(f)
else:
- f = self.get_filter_tuple(f)
+ conditions.append(self.prepare_filter_condition(f))
- tname = ('`tab' + f[0] + '`')
- if not tname in self.tables:
- self.append_table(tname)
+ def prepare_filter_condition(self, f):
+ """Returns a filter condition in the format:
- # prepare in condition
- if f[2] in ['in', 'not in']:
- opts = f[3]
- if not isinstance(opts, (list, tuple)):
- opts = f[3].split(",")
- opts = [frappe.db.escape(t.strip()) for t in opts]
- f[3] = '("{0}")'.format('", "'.join(opts))
- conditions.append('ifnull({tname}.{fname}, "") {operator} {value}'.format(
- tname=tname, fname=f[1], operator=f[2], value=f[3]))
- else:
- df = frappe.get_meta(f[0]).get("fields", {"fieldname": f[1]})
- df = df[0] if df else None
+ ifnull(`tabDocType`.`fieldname`, fallback) operator "value"
+ """
- if df and df.fieldtype=="Date":
- value, default_val = '"{0}"'.format(frappe.db.escape(getdate(f[3]).strftime("%Y-%m-%d"))), \
- "'0000-00-00'"
+ f = self.get_filter(f)
- elif df and df.fieldtype=="Datetime":
- value, default_val = '"{0}"'.format(frappe.db.escape(get_datetime(f[3]).strftime("%Y-%m-%d %H:%M:%S.%f"))), \
- "'0000-00-00 00:00:00'"
+ tname = ('`tab' + f.doctype + '`')
+ if not tname in self.tables:
+ self.append_table(tname)
- elif df and df.fieldtype=="Time":
- value, default_val = '"{0}"'.format(frappe.db.escape(get_time(f[3]).strftime("%H:%M:%S.%f"))), \
- "'00:00:00'"
+ # prepare in condition
+ if f.operator in ('in', 'not in'):
+ values = f.value
+ if not isinstance(values, (list, tuple)):
+ values = values.split(",")
- elif f[2] == "like" or (isinstance(f[3], basestring) and
- (not df or df.fieldtype not in ["Float", "Int", "Currency", "Percent", "Check"])):
- if f[2] == "like":
- # because "like" uses backslash (\) for escaping
- f[3] = f[3].replace("\\", "\\\\")
+ values = (frappe.db.escape(v.strip(), percent=False) for v in values)
+ values = '("{0}")'.format('", "'.join(values))
- value, default_val = '"{0}"'.format(frappe.db.escape(f[3])), '""'
- else:
- value, default_val = flt(f[3]), 0
+ condition = 'ifnull({tname}.{fname}, "") {operator} {value}'.format(
+ tname=tname, fname=f.fieldname, operator=f.operator, value=values)
- conditions.append('ifnull({tname}.{fname}, {default_val}) {operator} {value}'.format(
- tname=tname, fname=f[1], default_val=default_val, operator=f[2],
- value=value))
+ else:
+ df = frappe.get_meta(f.doctype).get("fields", {"fieldname": f.fieldname})
+ df = df[0] if df else None
- def get_filter_tuple(self, f):
+ if df and df.fieldtype=="Date":
+ value = getdate(f.value).strftime("%Y-%m-%d")
+ fallback = "'0000-00-00'"
+
+ elif df and df.fieldtype=="Datetime":
+ value = get_datetime(f.value).strftime("%Y-%m-%d %H:%M:%S.%f")
+ fallback = "'0000-00-00 00:00:00'"
+
+ elif df and df.fieldtype=="Time":
+ value = get_time(f.value).strftime("%H:%M:%S.%f")
+ fallback = "'00:00:00'"
+
+ elif f.operator in ("like", "not like") or (isinstance(f.value, basestring) and
+ (not df or df.fieldtype not in ["Float", "Int", "Currency", "Percent", "Check"])):
+ value = "" if f.value==None else f.value
+ fallback = '""'
+
+ if f.operator in ("like", "not like") and isinstance(value, basestring):
+ # because "like" uses backslash (\) for escaping
+ value = value.replace("\\", "\\\\").replace("%", "%%")
+
+ else:
+ value = flt(f.value)
+ fallback = 0
+
+ # put it inside double quotes
+ if isinstance(value, basestring):
+ value = '"{0}"'.format(frappe.db.escape(value, percent=False))
+
+ condition = 'ifnull({tname}.{fname}, {fallback}) {operator} {value}'.format(
+ tname=tname, fname=f.fieldname, fallback=fallback, operator=f.operator,
+ value=value)
+
+ return condition
+
+ def get_filter(self, f):
+ """Returns a _dict like
+
+ {
+ "doctype": "DocType",
+ "fieldname": "fieldname",
+ "operator": "=",
+ "value": "value"
+ }
+
+ """
if isinstance(f, dict):
key, value = f.items()[0]
f = self.make_filter_tuple(key, value)
@@ -262,15 +293,27 @@ class DatabaseQuery(object):
f = (self.doctype, f[0], f[1], f[2])
elif len(f) != 4:
- frappe.throw("Filter must have 4 values (doctype, fieldname, condition, value): " + str(f))
+ frappe.throw("Filter must have 4 values (doctype, fieldname, operator, value): {0}".format(str(f)))
- return list(f)
+ if not f[2]:
+ # if operator is missing
+ f[2] = "="
+
+ valid_operators = ("=", "!=", ">", "<", ">=", "<=", "like", "not like", "in", "not in")
+ if f[2] not in valid_operators:
+ frappe.throw("Operator must be one of {0}".format(", ".join(valid_operators)))
+
+ return frappe._dict({
+ "doctype": f[0],
+ "fieldname": f[1],
+ "operator": f[2],
+ "value": f[3]
+ })
def build_match_conditions(self, as_condition=True):
"""add match conditions if applicable"""
self.match_filters = []
self.match_conditions = []
-
only_if_shared = False
if not self.tables: self.extract_tables()
@@ -295,9 +338,9 @@ class DatabaseQuery(object):
self.add_user_permissions(user_permissions,
user_permission_doctypes=role_permissions.get("user_permission_doctypes").get("read"))
- # share is an OR condition, if there is a role permission
- if not only_if_shared and self.shared:
- self.or_conditions.append(self.get_share_condition())
+ if role_permissions.get("if_owner", {}).get("read"):
+ self.match_conditions.append("`tab{0}`.owner = '{1}'".format(self.doctype,
+ frappe.db.escape(frappe.session.user, percent=False)))
if as_condition:
conditions = ""
@@ -309,6 +352,11 @@ class DatabaseQuery(object):
if doctype_conditions:
conditions += (' and ' + doctype_conditions) if conditions else doctype_conditions
+ # share is an OR condition, if there is a role permission
+ if not only_if_shared and self.shared and conditions:
+ conditions = "({conditions}) or ({shared_condition})".format(
+ conditions=conditions, shared_condition=self.get_share_condition())
+
return conditions
else:
@@ -316,11 +364,10 @@ class DatabaseQuery(object):
def get_share_condition(self):
return """`tab{0}`.name in ({1})""".format(self.doctype, ", ".join(["'%s'"] * len(self.shared))) % \
- tuple([frappe.db.escape(s) for s in self.shared])
+ tuple([frappe.db.escape(s, percent=False) for s in self.shared])
def add_user_permissions(self, user_permissions, user_permission_doctypes=None):
- user_permission_doctypes = frappe.permissions.get_user_permission_doctypes(user_permission_doctypes,
- user_permissions)
+ user_permission_doctypes = frappe.permissions.get_user_permission_doctypes(user_permission_doctypes, user_permissions)
meta = frappe.get_meta(self.doctype)
for doctypes in user_permission_doctypes:
@@ -328,13 +375,17 @@ class DatabaseQuery(object):
match_conditions = []
# check in links
for df in meta.get_fields_to_check_permissions(doctypes):
- match_conditions.append("""(ifnull(`tab{doctype}`.`{fieldname}`, "")=""
- or `tab{doctype}`.`{fieldname}` in ({values}))""".format(
- doctype=self.doctype,
- fieldname=df.fieldname,
- values=", ".join([('"'+frappe.db.escape(v)+'"') for v in user_permissions[df.options]])
- ))
- match_filters[df.options] = user_permissions[df.options]
+ user_permission_values = user_permissions.get(df.options, [])
+
+ condition = 'ifnull(`tab{doctype}`.`{fieldname}`, "")=""'.format(doctype=self.doctype, fieldname=df.fieldname)
+ if user_permission_values:
+ condition += """ or `tab{doctype}`.`{fieldname}` in ({values})""".format(
+ doctype=self.doctype, fieldname=df.fieldname,
+ values=", ".join([('"'+frappe.db.escape(v, percent=False)+'"') for v in user_permission_values])
+ )
+ match_conditions.append("({condition})".format(condition=condition))
+
+ match_filters[df.options] = user_permission_values
if match_conditions:
self.match_conditions.append(" and ".join(match_conditions))
diff --git a/frappe/model/db_schema.py b/frappe/model/db_schema.py
index de3df36175..ff35518a24 100644
--- a/frappe/model/db_schema.py
+++ b/frappe/model/db_schema.py
@@ -12,10 +12,14 @@ import re
import os
import frappe
from frappe import _
-from frappe.utils import cstr, cint
+from frappe.utils import cstr, cint, flt
+import MySQLdb
class InvalidColumnName(frappe.ValidationError): pass
+varchar_len = '140'
+standard_varchar_columns = ('name', 'owner', 'modified_by', 'parent', 'parentfield', 'parenttype')
+
type_map = {
'Currency': ('decimal', '18,6')
,'Int': ('int', '11')
@@ -30,14 +34,14 @@ type_map = {
,'Datetime': ('datetime', '6')
,'Time': ('time', '6')
,'Text': ('text', '')
- ,'Data': ('varchar', '255')
- ,'Link': ('varchar', '255')
- ,'Dynamic Link':('varchar', '255')
- ,'Password': ('varchar', '255')
- ,'Select': ('varchar', '255')
- ,'Read Only': ('varchar', '255')
- ,'Attach': ('varchar', '255')
- ,'Attach Image':('varchar', '255')
+ ,'Data': ('varchar', varchar_len)
+ ,'Link': ('varchar', varchar_len)
+ ,'Dynamic Link':('varchar', varchar_len)
+ ,'Password': ('varchar', varchar_len)
+ ,'Select': ('varchar', varchar_len)
+ ,'Read Only': ('varchar', varchar_len)
+ ,'Attach': ('text', '')
+ ,'Attach Image':('text', '')
}
default_columns = ['name', 'creation', 'modified', 'modified_by', 'owner',
@@ -52,13 +56,15 @@ def updatedb(dt):
* updates columns
* updates indices
"""
- res = frappe.db.sql("select ifnull(issingle, 0) from tabDocType where name=%s", (dt,))
+ res = frappe.db.sql("select issingle from tabDocType where name=%s", (dt,))
if not res:
raise Exception, 'Wrong doctype "%s" in updatedb' % dt
if not res[0][0]:
- frappe.db.commit()
tab = DbTable(dt, 'tab')
+ tab.validate()
+
+ frappe.db.commit()
tab.sync()
frappe.db.begin()
@@ -75,18 +81,67 @@ class DbTable:
self.add_index = []
self.drop_index = []
-
self.set_default = []
# load
self.get_columns_from_docfields()
+ def validate(self):
+ """Check if change in varchar length isn't truncating the columns"""
+ if self.is_new():
+ return
+
+ self.get_columns_from_db()
+
+ columns = [frappe._dict({"fieldname": f, "fieldtype": "Data"}) for f in standard_varchar_columns]
+ columns += self.columns.values()
+
+ for col in columns:
+ if col.fieldtype in type_map and type_map[col.fieldtype][0]=="varchar":
+
+ # validate length range
+ new_length = cint(col.length) or cint(varchar_len)
+ if not (1 <= new_length <= 255):
+ frappe.throw(_("Length of {0} should be between 1 and 255").format(col.fieldname))
+
+ try:
+ # check for truncation
+ max_length = frappe.db.sql("""select max(char_length(`{fieldname}`)) from `tab{doctype}`"""\
+ .format(fieldname=col.fieldname, doctype=self.doctype))
+
+ except MySQLdb.OperationalError, e:
+ if e.args[0]==1054:
+ # Unknown column 'column_name' in 'field list'
+ continue
+
+ else:
+ raise
+
+ if max_length and max_length[0][0] > new_length:
+ current_type = self.current_columns[col.fieldname]["type"]
+ current_length = re.findall('varchar\(([\d]+)\)', current_type)
+ if not current_length:
+ # case when the field is no longer a varchar
+ continue
+
+ current_length = current_length[0]
+
+ if col.fieldname in self.columns:
+ self.columns[col.fieldname].length = current_length
+
+ frappe.msgprint(_("Reverting length to {0} for '{1}' in '{2}'; Setting the length as {3} will cause truncation of data.")\
+ .format(current_length, col.fieldname, self.doctype, new_length))
+
+
def sync(self):
- if not self.name in DbManager(frappe.db).get_tables_list(frappe.db.cur_db_name):
+ if self.is_new():
self.create()
else:
self.alter()
+ def is_new(self):
+ return self.name not in DbManager(frappe.db).get_tables_list(frappe.db.cur_db_name)
+
def create(self):
add_text = ''
@@ -100,21 +155,21 @@ class DbTable:
# create table
frappe.db.sql("""create table `%s` (
- name varchar(255) not null primary key,
+ name varchar({varchar_len}) not null primary key,
creation datetime(6),
modified datetime(6),
- modified_by varchar(255),
- owner varchar(255),
- docstatus int(1) default '0',
- parent varchar(255),
- parentfield varchar(255),
- parenttype varchar(255),
- idx int(8),
+ modified_by varchar({varchar_len}),
+ owner varchar({varchar_len}),
+ docstatus int(1) not null default '0',
+ parent varchar({varchar_len}),
+ parentfield varchar({varchar_len}),
+ parenttype varchar({varchar_len}),
+ idx int(8) not null default '0',
%sindex parent(parent))
ENGINE=InnoDB
ROW_FORMAT=COMPRESSED
CHARACTER SET=utf8mb4
- COLLATE=utf8mb4_unicode_ci""" % (self.name, add_text))
+ COLLATE=utf8mb4_unicode_ci""".format(varchar_len=varchar_len) % (self.name, add_text))
def get_column_definitions(self):
column_list = [] + default_columns
@@ -140,23 +195,37 @@ class DbTable:
get columns from docfields and custom fields
"""
fl = frappe.db.sql("SELECT * FROM tabDocField WHERE parent = %s", self.doctype, as_dict = 1)
+ lengths = {}
precisions = {}
+ uniques = {}
- if not frappe.flags.in_install:
+ if not frappe.flags.in_install_db and frappe.flags.in_install != "frappe":
custom_fl = frappe.db.sql("""\
SELECT * FROM `tabCustom Field`
WHERE dt = %s AND docstatus < 2""", (self.doctype,), as_dict=1)
if custom_fl: fl += custom_fl
- # get precision from property setters
- for ps in frappe.get_all("Property Setter", fields=["field_name", "value"],
- filters={"doc_type": self.doctype, "doctype_or_field": "DocField", "property": "precision"}):
- precisions[ps.field_name] = ps.value
+ # apply length, precision and unique from property setters
+ for ps in frappe.get_all("Property Setter", fields=["field_name", "property", "value"],
+ filters={
+ "doc_type": self.doctype,
+ "doctype_or_field": "DocField",
+ "property": ["in", ["precision", "length", "unique"]]
+ }):
+
+ if ps.property=="length":
+ lengths[ps.field_name] = cint(ps.value)
+
+ elif ps.property=="precision":
+ precisions[ps.field_name] = cint(ps.value)
+
+ elif ps.property=="unique":
+ uniques[ps.field_name] = cint(ps.value)
for f in fl:
self.columns[f['fieldname']] = DbColumn(self, f['fieldname'],
- f['fieldtype'], f.get('length'), f.get('default'), f.get('search_index'),
- f.get('options'), f.get('unique'), precisions.get(f['fieldname']) or f.get('precision'))
+ f['fieldtype'], lengths.get(f["fieldname"]) or f.get('length'), f.get('default'), f.get('search_index'),
+ f.get('options'), uniques.get(f["fieldname"], f.get('unique')), precisions.get(f['fieldname']) or f.get('precision'))
def get_columns_from_db(self):
self.show_columns = frappe.db.sql("desc `%s`" % self.name)
@@ -196,7 +265,6 @@ class DbTable:
frappe.db.sql("set foreign_key_checks=1")
def alter(self):
- self.get_columns_from_db()
for col in self.columns.values():
col.build_for_alter_table(self.current_columns.get(col.fieldname, None))
@@ -226,15 +294,32 @@ class DbTable:
if col.fieldname=="name":
continue
- if not col.default:
+ if col.fieldtype in ("Check", "Int"):
+ col_default = cint(col.default)
+
+ elif col.fieldtype in ("Currency", "Float", "Percent"):
+ col_default = flt(col.default)
+
+ elif not col.default:
col_default = "null"
+
else:
col_default = '"{}"'.format(col.default.replace('"', '\\"'))
query.append('alter column `{}` set default {}'.format(col.fieldname, col_default))
if query:
- frappe.db.sql("alter table `{}` {}".format(self.name, ", ".join(query)))
+ try:
+ frappe.db.sql("alter table `{}` {}".format(self.name, ", ".join(query)))
+ except Exception, e:
+ # sanitize
+ if e.args[0]==1060:
+ frappe.throw(str(e))
+ elif e.args[0]==1062:
+ fieldname = str(e).split("'")[-2]
+ frappe.throw(_("{0} field cannot be set as unique in {1}, as there are non-unique existing values".format(fieldname, self.name)))
+ else:
+ raise e
class DbColumn:
def __init__(self, table, fieldname, fieldtype, length, default,
@@ -250,12 +335,20 @@ class DbColumn:
self.precision = precision
def get_definition(self, with_default=1):
- column_def = get_definition(self.fieldtype, self.precision)
+ column_def = get_definition(self.fieldtype, precision=self.precision, length=self.length)
if not column_def:
return column_def
- if self.default and (self.default not in default_shortcuts) \
+ if self.fieldtype in ("Check", "Int"):
+ default_value = cint(self.default) or 0
+ column_def += ' not null default {0}'.format(default_value)
+
+ elif self.fieldtype in ("Currency", "Float", "Percent"):
+ default_value = flt(self.default) or 0
+ column_def += ' not null default {0}'.format(default_value)
+
+ elif self.default and (self.default not in default_shortcuts) \
and not self.default.startswith(":") and column_def not in ('text', 'longtext'):
column_def += ' default "' + self.default.replace('"', '\"') + '"'
@@ -265,7 +358,7 @@ class DbColumn:
return column_def
def build_for_alter_table(self, current_def):
- column_def = get_definition(self.fieldtype)
+ column_def = get_definition(self.fieldtype, self.precision, self.length)
# no columns
if not column_def:
@@ -278,21 +371,11 @@ class DbColumn:
return
# type
- if (current_def['type'] != column_def) or (self.unique and not current_def['unique'] \
- and column_def in ('text', 'longtext')):
+ if (current_def['type'] != column_def) or \
+ ((self.unique and not current_def['unique']) and column_def not in ('text', 'longtext')):
self.table.change_type.append(self)
else:
- # index
- if (current_def['index'] and not self.set_index):
- self.table.drop_index.append(self)
-
- if (current_def['unique'] and not self.unique) and not (column_def in ('text', 'longtext')):
- self.table.drop_index.append(self)
-
- if (not current_def['index'] and self.set_index) and not (column_def in ('text', 'longtext')):
- self.table.add_index.append(self)
-
# default
if (self.default_changed(current_def) \
and (self.default not in default_shortcuts) \
@@ -300,6 +383,15 @@ class DbColumn:
and not (column_def in ['text','longtext'])):
self.table.set_default.append(self)
+ # index should be applied or dropped irrespective of type change
+ if ( (current_def['index'] and not self.set_index and not self.unique)
+ or (current_def['unique'] and not self.unique) ):
+ # to drop unique you have to drop index
+ self.table.drop_index.append(self)
+
+ elif (not current_def['index'] and self.set_index) and not (column_def in ('text', 'longtext')):
+ self.table.add_index.append(self)
+
def default_changed(self, current_def):
if "decimal" in current_def['type']:
return self.default_changed_for_decimal(current_def)
@@ -437,7 +529,7 @@ def validate_column_name(n):
def remove_all_foreign_keys():
frappe.db.sql("set foreign_key_checks = 0")
frappe.db.commit()
- for t in frappe.db.sql("select name from tabDocType where ifnull(issingle,0)=0"):
+ for t in frappe.db.sql("select name from tabDocType where issingle=0"):
dbtab = DbTable(t[0])
try:
fklist = dbtab.get_foreign_keys()
@@ -450,23 +542,30 @@ def remove_all_foreign_keys():
for f in fklist:
frappe.db.sql("alter table `tab%s` drop foreign key `%s`" % (t[0], f[1]))
-def get_definition(fieldtype, precision=None):
+def get_definition(fieldtype, precision=None, length=None):
d = type_map.get(fieldtype)
if not d:
return
- ret = d[0]
+ coltype = d[0]
+ size = None
if d[1]:
- length = d[1]
- if fieldtype in ["Float", "Currency", "Percent"] and cint(precision) > 6:
- length = '18,9'
- ret += '(' + length + ')'
+ size = d[1]
- return ret
+ if size:
+ if fieldtype in ["Float", "Currency", "Percent"] and cint(precision) > 6:
+ size = '18,9'
+
+ if coltype == "varchar" and length:
+ size = length
+
+ if size is not None:
+ coltype = "{coltype}({size})".format(coltype=coltype, size=size)
+
+ return coltype
def add_column(doctype, column_name, fieldtype, precision=None):
frappe.db.commit()
frappe.db.sql("alter table `tab%s` add column %s %s" % (doctype,
column_name, get_definition(fieldtype, precision)))
-
diff --git a/frappe/model/delete_doc.py b/frappe/model/delete_doc.py
index 3cedda56b5..bae7bca99c 100644
--- a/frappe/model/delete_doc.py
+++ b/frappe/model/delete_doc.py
@@ -82,9 +82,11 @@ def delete_doc(doctype=None, name=None, force=0, ignore_doctypes=None, for_reloa
update_naming_series(doc)
delete_from_table(doctype, name, ignore_doctypes, doc)
+ doc.run_method("after_delete")
if doc:
try:
+ doc.notify_update()
insert_feed(doc)
except ImportError:
pass
@@ -105,7 +107,7 @@ def delete_from_table(doctype, name, ignore_doctypes, doc):
if doctype!="DocType" and doctype==name:
frappe.db.sql("delete from `tabSingles` where doctype=%s", name)
else:
- frappe.db.sql("delete from `tab%s` where name=%s" % (doctype, "%s"), (name,))
+ frappe.db.sql("delete from `tab%s` where name=%s" % (frappe.db.escape(doctype), "%s"), (name,))
# get child tables
if doc:
@@ -150,41 +152,58 @@ def check_if_doc_is_linked(doc, method="Delete"):
if item and item.parent != doc.name and ((method=="Delete" and item.docstatus<2) or
(method=="Cancel" and item.docstatus==1)):
+ # raise exception only if
+ # linked to an non-cancelled doc when deleting
+ # or linked to a submitted doc when cancelling
frappe.throw(_("Cannot delete or cancel because {0} {1} is linked with {2} {3}").format(doc.doctype,
doc.name, item.parenttype if item.parent else link_dt, item.parent or item.name),
frappe.LinkExistsError)
-def check_if_doc_is_dynamically_linked(doc):
+def check_if_doc_is_dynamically_linked(doc, method="Delete"):
for query in dynamic_link_queries:
for df in frappe.db.sql(query, as_dict=True):
if frappe.get_meta(df.parent).issingle:
# dynamic link in single doc
refdoc = frappe.db.get_singles_dict(df.parent)
- if refdoc.get(df.options)==doc.doctype and refdoc.get(df.fieldname)==doc.name:
+ if (refdoc.get(df.options)==doc.doctype
+ and refdoc.get(df.fieldname)==doc.name
+ and ((method=="Delete" and refdoc.docstatus < 2)
+ or (method=="Cancel" and refdoc.docstatus==1))
+ ):
+ # raise exception only if
+ # linked to an non-cancelled doc when deleting
+ # or linked to a submitted doc when cancelling
frappe.throw(_("Cannot delete or cancel because {0} {1} is linked with {2} {3}").format(doc.doctype,
doc.name, df.parent, ""), frappe.LinkExistsError)
else:
-
# dynamic link in table
- for name in frappe.db.sql_list("""select name from `tab{parent}` where
- {options}=%s and {fieldname}=%s""".format(**df), (doc.doctype, doc.name)):
- frappe.throw(_("Cannot delete or cancel because {0} {1} is linked with {2} {3}").format(doc.doctype,
- doc.name, df.parent, name), frappe.LinkExistsError)
+ for refdoc in frappe.db.sql("""select name, docstatus from `tab{parent}` where
+ {options}=%s and {fieldname}=%s""".format(**df), (doc.doctype, doc.name), as_dict=True):
+
+ if ((method=="Delete" and refdoc.docstatus < 2) or (method=="Cancel" and refdoc.docstatus==1)):
+ # raise exception only if
+ # linked to an non-cancelled doc when deleting
+ # or linked to a submitted doc when cancelling
+ frappe.throw(_("Cannot delete or cancel because {0} {1} is linked with {2} {3}")\
+ .format(doc.doctype, doc.name, df.parent, refdoc.name), frappe.LinkExistsError)
def delete_linked_todos(doc):
delete_doc("ToDo", frappe.db.sql_list("""select name from `tabToDo`
- where reference_type=%s and reference_name=%s""", (doc.doctype, doc.name)))
+ where reference_type=%s and reference_name=%s""", (doc.doctype, doc.name)),
+ ignore_permissions=True)
def delete_linked_comments(doc):
"""Delete comments from the document"""
-
delete_doc("Comment", frappe.db.sql_list("""select name from `tabComment`
- where comment_doctype=%s and comment_docname=%s""", (doc.doctype, doc.name)), ignore_on_trash=True)
+ where comment_doctype=%s and comment_docname=%s""", (doc.doctype, doc.name)), ignore_on_trash=True,
+ ignore_permissions=True)
def delete_linked_communications(doc):
- delete_doc("Communication", frappe.db.sql_list("""select name from `tabCommunication`
- where reference_doctype=%s and reference_name=%s""", (doc.doctype, doc.name)))
+ # make communications orphans
+ frappe.db.sql("""update `tabCommunication`
+ set reference_doctype=null, reference_name=null
+ where reference_doctype=%s and reference_name=%s""", (doc.doctype, doc.name))
def insert_feed(doc):
from frappe.utils import get_fullname
diff --git a/frappe/model/document.py b/frappe/model/document.py
index 547bdc6932..3c308f1b8a 100644
--- a/frappe/model/document.py
+++ b/frappe/model/document.py
@@ -58,6 +58,8 @@ class Document(BaseDocument):
all values (including child documents) from the database.
"""
self.doctype = self.name = None
+ self._default_new_docs = {}
+ self.flags = frappe._dict()
if arg1 and isinstance(arg1, basestring):
if not arg2:
@@ -83,8 +85,9 @@ class Document(BaseDocument):
# incorrect arguments. let's not proceed.
raise frappe.DataError("Document({0}, {1})".format(arg1, arg2))
- self._default_new_docs = {}
- self.flags = frappe._dict()
+ def reload(self):
+ """Reload document from database"""
+ self.load_from_db()
def load_from_db(self):
"""Load document and children from database and create properties
@@ -145,6 +148,17 @@ class Document(BaseDocument):
return True
return frappe.has_permission(self.doctype, permtype, self, verbose=verbose)
+ def has_website_permission(self, permtype="read", verbose=False):
+ """Call `frappe.has_website_permission` if `self.flags.ignore_permissions`
+ is not set.
+
+ :param permtype: one of `read`, `write`, `submit`, `cancel`, `delete`"""
+ if self.flags.ignore_permissions:
+ return True
+
+ return (frappe.has_website_permission(self.doctype, permtype, self, verbose=verbose)
+ or self.has_permission(permtype, verbose=verbose))
+
def raise_no_permission_to(self, perm_type):
"""Raise `frappe.PermissionError`."""
msg = _("No permission to {0} {1} {2}".format(perm_type, self.doctype, self.name or ""))
@@ -167,7 +181,7 @@ class Document(BaseDocument):
self.check_permission("create")
self._set_defaults()
- self._set_docstatus_user_and_timestamp()
+ self.set_docstatus_user_and_timestamp()
self.check_if_latest()
self.run_method("before_insert")
self.set_new_name()
@@ -218,7 +232,7 @@ class Document(BaseDocument):
self.check_permission("write", "save")
- self._set_docstatus_user_and_timestamp()
+ self.set_docstatus_user_and_timestamp()
self.check_if_latest()
self.set_parent_in_children()
self.validate_higher_perm_levels()
@@ -268,6 +282,25 @@ class Document(BaseDocument):
for d in self.get_all_children():
set_new_name(d)
+ def set_title_field(self):
+ """Set title field based on template"""
+ def get_values():
+ values = self.as_dict()
+ # format values
+ for key, value in values.iteritems():
+ if value==None:
+ values[key] = ""
+ return values
+
+ if self.meta.get("title_field")=="title":
+ df = self.meta.get_field(self.meta.title_field)
+ if df.options:
+ self.set(df.fieldname, df.options.format(**get_values()))
+ elif self.is_new() and not self.get(df.fieldname) and df.default:
+ # set default title for new transactions (if default)
+ self.set(df.fieldname, df.default.format(**get_values()))
+
+
def update_single(self, d):
"""Updates values for Single type Document in `tabSingles`."""
frappe.db.sql("""delete from tabSingles where doctype=%s""", self.doctype)
@@ -276,7 +309,10 @@ class Document(BaseDocument):
frappe.db.sql("""insert into tabSingles(doctype, field, value)
values (%s, %s, %s)""", (self.doctype, field, value))
- def _set_docstatus_user_and_timestamp(self):
+ if self.doctype in frappe.db.value_cache:
+ del frappe.db.value_cache[self.doctype]
+
+ def set_docstatus_user_and_timestamp(self):
self._original_modified = self.modified
self.modified = now()
self.modified_by = frappe.session.user
@@ -301,11 +337,13 @@ class Document(BaseDocument):
self._validate_links()
self._validate_selects()
self._validate_constants()
+ self._validate_length()
children = self.get_all_children()
for d in children:
d._validate_selects()
d._validate_constants()
+ d._validate_length()
# extract images after validations to save processing if some validation error is raised
self._extract_images_from_text_editor()
@@ -438,6 +476,10 @@ class Document(BaseDocument):
self._validate_update_after_submit()
for d in self.get_all_children():
+ if d.is_new() and self.meta.get_field(d.parentfield).allow_on_submit:
+ # in case of a new row, don't validate allow on submit, if table is allow on submit
+ continue
+
d._validate_update_after_submit()
# TODO check only allowed values are updated
@@ -457,7 +499,7 @@ class Document(BaseDocument):
msgprint(msg)
if frappe.flags.print_messages:
- print self.as_dict()
+ print self.as_json().encode("utf-8")
raise frappe.MandatoryError(", ".join((each[0] for each in missing)))
@@ -535,7 +577,11 @@ class Document(BaseDocument):
- `validate`, `before_save` for **Save**.
- `validate`, `before_submit` for **Submit**.
- `before_cancel` for **Cancel**
- - `before_update_after_submit` for **Update after Submit**"""
+ - `before_update_after_submit` for **Update after Submit**
+
+ Will also update title_field if set"""
+ self.set_title_field()
+
if self.flags.ignore_validate:
return
@@ -572,15 +618,50 @@ class Document(BaseDocument):
elif self._action=="update_after_submit":
self.run_method("on_update_after_submit")
- frappe.cache().hdel("last_modified", self.doctype)
+ self.clear_cache()
+ self.notify_update()
self.latest = None
+ def clear_cache(self):
+ frappe.cache().hdel("last_modified", self.doctype)
+ self.clear_linked_with_cache()
+
+ def clear_linked_with_cache(self):
+ cache = frappe.cache()
+ def _clear_cache(d):
+ for df in (d.meta.get_link_fields() + d.meta.get_dynamic_link_fields()):
+ if d.get(df.fieldname):
+ doctype = df.options if df.fieldtype=="Link" else d.get(df.options)
+ name = d.get(df.fieldname)
+
+ if df.fieldtype=="Dynamic Link":
+ # clear linked doctypes list
+ cache.hdel("linked_doctypes", doctype)
+
+ # delete linked with cache for all users
+ cache.delete_value("user:*:linked_with:{doctype}:{name}".format(doctype=doctype, name=name))
+
+ _clear_cache(self)
+ for d in self.get_all_children():
+ _clear_cache(d)
+
+ def notify_update(self):
+ """Publish realtime that the current document is modified"""
+ frappe.publish_realtime("doc_update", {"modified": self.modified, "doctype": self.doctype, "name": self.name},
+ doctype=self.doctype, docname=self.name)
+
+ if not self.meta.get("read_only") and not self.meta.get("issingle") and \
+ not self.meta.get("istable"):
+ frappe.publish_realtime("list_update", {"doctype": self.doctype})
+
+
def check_no_back_links_exist(self):
"""Check if document links to any active document before Cancel."""
- from frappe.model.delete_doc import check_if_doc_is_linked
+ from frappe.model.delete_doc import check_if_doc_is_linked, check_if_doc_is_dynamically_linked
if not self.flags.ignore_links:
check_if_doc_is_linked(self, method="Cancel")
+ check_if_doc_is_dynamically_linked(self, method="Cancel")
@staticmethod
def whitelist(f):
diff --git a/frappe/model/mapper.py b/frappe/model/mapper.py
index 43c8d2bb8a..8623fe83c9 100644
--- a/frappe/model/mapper.py
+++ b/frappe/model/mapper.py
@@ -33,6 +33,17 @@ def get_mapped_doc(from_doctype, from_docname, table_maps, target_doc=None,
for df in source_doc.meta.get_table_fields():
source_child_doctype = df.options
table_map = table_maps.get(source_child_doctype)
+
+ # if table_map isn't explicitly specified check if both source and target have the same fieldname and same table options and both of them don't have no_copy
+ if not table_map:
+ target_df = target_doc.meta.get_field(df.fieldname)
+ if target_df:
+ target_child_doctype = target_df.options
+ if target_df and target_child_doctype==source_child_doctype and not df.no_copy and not target_df.no_copy:
+ table_map = {
+ "doctype": target_child_doctype
+ }
+
if table_map:
for source_d in source_doc.get(df.fieldname):
if "condition" in table_map:
@@ -122,10 +133,7 @@ def map_fields(source_doc, target_doc, table_map, source_parent):
map_fetch_fields(target_doc, df, no_copy_fields)
def map_fetch_fields(target_doc, df, no_copy_fields):
- try:
- linked_doc = frappe.get_doc(df.options, target_doc.get(df.fieldname))
- except:
- return
+ linked_doc = None
# options should be like "link_fieldname.fieldname_in_liked_doc"
for fetch_df in target_doc.meta.get("fields", {"options": "^{0}.".format(df.fieldname)}):
@@ -134,6 +142,13 @@ def map_fetch_fields(target_doc, df, no_copy_fields):
if not target_doc.get(fetch_df.fieldname) and fetch_df.fieldname not in no_copy_fields:
source_fieldname = fetch_df.options.split(".")[1]
+
+ if not linked_doc:
+ try:
+ linked_doc = frappe.get_doc(df.options, target_doc.get(df.fieldname))
+ except:
+ return
+
val = linked_doc.get(source_fieldname)
if val not in (None, ""):
@@ -145,6 +160,7 @@ def map_child_doc(source_d, target_parent, table_map, source_parent=None):
target_d = frappe.new_doc(target_child_doctype, target_parent, target_parentfield)
map_doc(source_d, target_d, table_map, source_parent)
+
target_d.idx = None
target_parent.append(target_parentfield, target_d)
return target_d
diff --git a/frappe/model/meta.py b/frappe/model/meta.py
index 025dbd21a3..c405196278 100644
--- a/frappe/model/meta.py
+++ b/frappe/model/meta.py
@@ -60,6 +60,9 @@ class Meta(Document):
def get_link_fields(self):
return self.get("fields", {"fieldtype": "Link", "options":["!=", "[Select]"]})
+ def get_dynamic_link_fields(self):
+ return self.get("fields", {"fieldtype": "Dynamic Link"})
+
def get_select_fields(self):
return self.get("fields", {"fieldtype": "Select", "options":["not in",
["[Select]", "Loading..."]]})
@@ -161,42 +164,26 @@ class Meta(Document):
def sort_fields(self):
"""sort on basis of previous_field"""
- newlist = []
- pending = self.get("fields")
-
if self.get("_idx"):
+ newlist = []
+ pending = self.get("fields")
+
for fieldname in json.loads(self.get("_idx")):
d = self.get("fields", {"fieldname": fieldname}, limit=1)
if d:
newlist.append(d[0])
pending.remove(d[0])
- else:
- maxloops = 20
- while (pending and maxloops>0):
- maxloops -= 1
- for d in pending[:]:
- if d.get("previous_field"):
- # field already added
- for n in newlist:
- if n.fieldname==d.previous_field:
- newlist.insert(newlist.index(n)+1, d)
- pending.remove(d)
- break
- else:
- newlist.append(d)
- pending.remove(d)
+
+ if pending:
+ newlist += pending
+
+ # renum
+ idx = 1
+ for d in newlist:
+ d.idx = idx
+ idx += 1
- # recurring at end
- if pending:
- newlist += pending
-
- # renum
- idx = 1
- for d in newlist:
- d.idx = idx
- idx += 1
-
- self.set("fields", newlist)
+ self.set("fields", newlist)
def get_fields_to_check_permissions(self, user_permission_doctypes):
fields = self.get("fields", {
@@ -256,16 +243,25 @@ def get_field_currency(df, doc=None):
if not doc:
return None
-
- if ":" in cstr(df.get("options")):
- split_opts = df.get("options").split(":")
- if len(split_opts)==3:
- currency = frappe.db.get_value(split_opts[0], doc.get(split_opts[1]),
- split_opts[2])
- else:
- currency = doc.get(df.get("options"))
-
- return currency
+
+ if not getattr(frappe.local, "field_currency", None):
+ frappe.local.field_currency = frappe._dict()
+
+ if not frappe.local.field_currency.get((doc.doctype, doc.parent or doc.name), {}).get(df.fieldname):
+ if ":" in cstr(df.get("options")):
+ split_opts = df.get("options").split(":")
+ if len(split_opts)==3:
+ currency = frappe.db.get_value(split_opts[0], doc.get(split_opts[1]), split_opts[2])
+ else:
+ currency = doc.get(df.get("options"))
+ if not currency and doc.parent:
+ currency = frappe.db.get_value(doc.parenttype, doc.parent, df.get("options"))
+
+ if currency:
+ frappe.local.field_currency.setdefault((doc.doctype, doc.parent or doc.name), frappe._dict())\
+ .setdefault(df.fieldname, currency)
+
+ return frappe.local.field_currency.get((doc.doctype, doc.parent or doc.name), {}).get(df.fieldname)
def get_field_precision(df, doc=None, currency=None):
"""get precision based on DocField options and fieldvalue in doc"""
@@ -319,22 +315,29 @@ def trim_tables():
doctype = doctype.name
columns = frappe.db.get_table_columns(doctype)
fields = [df.fieldname for df in frappe.get_meta(doctype).fields if df.fieldtype not in no_value_fields]
- columns_to_remove = [f for f in list(set(columns) - set(fields)) if f not in ignore_fields]
+ columns_to_remove = [f for f in list(set(columns) - set(fields)) if f not in ignore_fields
+ and not f.startswith("_")]
if columns_to_remove:
+ print doctype, "columns removed:", columns_to_remove
columns_to_remove = ", ".join(["drop `{0}`".format(c) for c in columns_to_remove])
query = """alter table `tab{doctype}` {columns}""".format(
doctype=doctype, columns=columns_to_remove)
frappe.db.sql_ddl(query)
def clear_cache(doctype=None):
- frappe.cache().delete_value("is_table")
- frappe.cache().delete_value("doctype_modules")
+ cache = frappe.cache()
- groups = ["meta", "form_meta", "table_columns", "last_modified"]
+ cache.delete_value("is_table")
+ cache.delete_value("doctype_modules")
+
+ groups = ["meta", "form_meta", "table_columns", "last_modified", "linked_doctypes"]
def clear_single(dt):
for name in groups:
- frappe.cache().hdel(name, dt)
+ cache.hdel(name, dt)
+
+ # also clear linked_with list cache
+ cache.delete_keys("user:*:linked_with:{doctype}:".format(doctype=doctype))
if doctype:
clear_single(doctype)
@@ -351,5 +354,5 @@ def clear_cache(doctype=None):
else:
# clear all
for name in groups:
- frappe.cache().delete_value(name)
+ cache.delete_value(name)
diff --git a/frappe/model/naming.py b/frappe/model/naming.py
index 3a7a4a7cb6..5152e83df0 100644
--- a/frappe/model/naming.py
+++ b/frappe/model/naming.py
@@ -82,7 +82,7 @@ def make_autoname(key, doctype=''):
DE/09/01/0001 where 09 is the year, 01 is the month and 0001 is the series
"""
if key=="hash":
- return frappe.generate_hash(doctype)[:10]
+ return frappe.generate_hash(doctype, 10)
if not "#" in key:
key = key + ".#####"
@@ -176,8 +176,8 @@ def _set_amended_name(doc):
def append_number_if_name_exists(doc):
if frappe.db.exists(doc.doctype, doc.name):
last = frappe.db.sql("""select name from `tab{}`
- where name regexp '{}-[[:digit:]]+'
- order by name desc limit 1""".format(doc.doctype, doc.name))
+ where name regexp '^{}-[[:digit:]]+'
+ order by length(name) desc, name desc limit 1""".format(doc.doctype, doc.name))
if last:
count = str(cint(last[0][0].rsplit("-", 1)[1]) + 1)
diff --git a/frappe/model/rename_doc.py b/frappe/model/rename_doc.py
index f3a6605eb0..d1f9c9b02e 100644
--- a/frappe/model/rename_doc.py
+++ b/frappe/model/rename_doc.py
@@ -66,8 +66,9 @@ def rename_doc(doctype, old, new, force=False, merge=False, ignore_permissions=F
def update_attachments(doctype, old, new):
try:
- frappe.db.sql("""update `tabFile Data` set attached_to_name=%s
- where attached_to_name=%s and attached_to_doctype=%s""", (new, old, doctype))
+ if old != "File Data" and doctype != "DocType":
+ frappe.db.sql("""update `tabFile` set attached_to_name=%s
+ where attached_to_name=%s and attached_to_doctype=%s""", (new, old, doctype))
except Exception, e:
if e.args[0]!=1054: # in patch?
raise
@@ -78,13 +79,13 @@ def rename_versions(doctype, old, new):
def rename_parent_and_child(doctype, old, new, meta):
# rename the doc
- frappe.db.sql("update `tab%s` set name=%s where name=%s" % (doctype, '%s', '%s'),
+ frappe.db.sql("update `tab%s` set name=%s where name=%s" % (frappe.db.escape(doctype), '%s', '%s'),
(new, old))
update_child_docs(old, new, meta)
def validate_rename(doctype, new, meta, merge, force, ignore_permissions):
# using for update so that it gets locked and someone else cannot edit it while this rename is going on!
- exists = frappe.db.sql("select name from `tab{doctype}` where name=%s for update".format(doctype=doctype), new)
+ exists = frappe.db.sql("select name from `tab{doctype}` where name=%s for update".format(doctype=frappe.db.escape(doctype)), new)
exists = exists[0][0] if exists else None
if merge and not exists:
@@ -96,7 +97,7 @@ def validate_rename(doctype, new, meta, merge, force, ignore_permissions):
if not (ignore_permissions or frappe.has_permission(doctype, "write")):
frappe.msgprint(_("You need write permission to rename"), raise_exception=1)
- if not force and not meta.allow_rename:
+ if not (force or ignore_permissions) and not meta.allow_rename:
frappe.msgprint(_("{0} not allowed to be renamed").format(_(doctype)), raise_exception=1)
# validate naming like it's done in doc.py
@@ -129,7 +130,7 @@ def update_child_docs(old, new, meta):
# update "parent"
for df in meta.get_table_fields():
frappe.db.sql("update `tab%s` set parent=%s where parent=%s" \
- % (df.options, '%s', '%s'), (new, old))
+ % (frappe.db.escape(df.options), '%s', '%s'), (new, old))
def update_link_field_values(link_fields, old, new, doctype):
for field in link_fields:
@@ -145,15 +146,15 @@ def update_link_field_values(link_fields, old, new, doctype):
frappe.db.sql("""\
update `tab%s` set `%s`=%s
where `%s`=%s""" \
- % (parent, field['fieldname'], '%s',
- field['fieldname'], '%s'),
+ % (frappe.db.escape(parent), frappe.db.escape(field['fieldname']), '%s',
+ frappe.db.escape(field['fieldname']), '%s'),
(new, old))
def get_link_fields(doctype):
# get link fields from tabDocField
link_fields = frappe.db.sql("""\
select parent, fieldname,
- (select ifnull(issingle, 0) from tabDocType dt
+ (select issingle from tabDocType dt
where dt.name = df.parent) as issingle
from tabDocField df
where
@@ -162,7 +163,7 @@ def get_link_fields(doctype):
# get link fields from tabCustom Field
custom_link_fields = frappe.db.sql("""\
select dt as parent, fieldname,
- (select ifnull(issingle, 0) from tabDocType dt
+ (select issingle from tabDocType dt
where dt.name = df.dt) as issingle
from `tabCustom Field` df
where
@@ -174,7 +175,7 @@ def get_link_fields(doctype):
# remove fields whose options have been changed using property setter
property_setter_link_fields = frappe.db.sql("""\
select ps.doc_type as parent, ps.field_name as fieldname,
- (select ifnull(issingle, 0) from tabDocType dt
+ (select issingle from tabDocType dt
where dt.name = ps.doc_type) as issingle
from `tabProperty Setter` ps
where
@@ -216,24 +217,24 @@ def get_select_fields(old, new):
# get link fields from tabDocField
select_fields = frappe.db.sql("""\
select parent, fieldname,
- (select ifnull(issingle, 0) from tabDocType dt
+ (select issingle from tabDocType dt
where dt.name = df.parent) as issingle
from tabDocField df
where
df.parent != %s and df.fieldtype = 'Select' and
df.options like "%%%%%s%%%%" """ \
- % ('%s', old), (new,), as_dict=1)
+ % ('%s', frappe.db.escape(old)), (new,), as_dict=1)
# get link fields from tabCustom Field
custom_select_fields = frappe.db.sql("""\
select dt as parent, fieldname,
- (select ifnull(issingle, 0) from tabDocType dt
+ (select issingle from tabDocType dt
where dt.name = df.dt) as issingle
from `tabCustom Field` df
where
df.dt != %s and df.fieldtype = 'Select' and
df.options like "%%%%%s%%%%" """ \
- % ('%s', old), (new,), as_dict=1)
+ % ('%s', frappe.db.escape(old)), (new,), as_dict=1)
# add custom link fields list to link fields list
select_fields += custom_select_fields
@@ -241,7 +242,7 @@ def get_select_fields(old, new):
# remove fields whose options have been changed using property setter
property_setter_select_fields = frappe.db.sql("""\
select ps.doc_type as parent, ps.field_name as fieldname,
- (select ifnull(issingle, 0) from tabDocType dt
+ (select issingle from tabDocType dt
where dt.name = ps.doc_type) as issingle
from `tabProperty Setter` ps
where
@@ -249,7 +250,7 @@ def get_select_fields(old, new):
ps.property_type='options' and
ps.field_name is not null and
ps.value like "%%%%%s%%%%" """ \
- % ('%s', old), (new,), as_dict=1)
+ % ('%s', frappe.db.escape(old)), (new,), as_dict=1)
select_fields += property_setter_select_fields
@@ -261,14 +262,14 @@ def update_select_field_values(old, new):
where
parent != %s and fieldtype = 'Select' and
(options like "%%%%\\n%s%%%%" or options like "%%%%%s\\n%%%%")""" % \
- ('%s', '%s', '%s', old, old), (old, new, new))
+ ('%s', '%s', '%s', frappe.db.escape(old), frappe.db.escape(old)), (old, new, new))
frappe.db.sql("""\
update `tabCustom Field` set options=replace(options, %s, %s)
where
dt != %s and fieldtype = 'Select' and
(options like "%%%%\\n%s%%%%" or options like "%%%%%s\\n%%%%")""" % \
- ('%s', '%s', '%s', old, old), (old, new, new))
+ ('%s', '%s', '%s', frappe.db.escape(old), frappe.db.escape(old)), (old, new, new))
frappe.db.sql("""\
update `tabProperty Setter` set value=replace(value, %s, %s)
@@ -276,7 +277,7 @@ def update_select_field_values(old, new):
doc_type != %s and field_name is not null and
property='options' and
(value like "%%%%\\n%s%%%%" or value like "%%%%%s\\n%%%%")""" % \
- ('%s', '%s', '%s', old, old), (old, new, new))
+ ('%s', '%s', '%s', frappe.db.escape(old), frappe.db.escape(old)), (old, new, new))
def update_parenttype_values(old, new):
child_doctypes = frappe.db.sql("""\
@@ -332,3 +333,38 @@ def rename_dynamic_links(doctype, old, new):
frappe.db.sql("""update `tab{parent}` set {fieldname}=%s
where name=%s""".format(**df), (new, to_change))
+
+def bulk_rename(doctype, rows=None, via_console = False):
+ """Bulk rename documents
+
+ :param doctype: DocType to be renamed
+ :param rows: list of documents as `((oldname, newname), ..)`"""
+ if not rows:
+ frappe.throw(_("Please select a valid csv file with data"))
+
+ if not via_console:
+ max_rows = 500
+ if len(rows) > max_rows:
+ frappe.throw(_("Maximum {0} rows allowed").format(max_rows))
+
+ rename_log = []
+ for row in rows:
+ # if row has some content
+ if len(row) > 1 and row[0] and row[1]:
+ try:
+ if rename_doc(doctype, row[0], row[1]):
+ msg = _("Successful: {0} to {1}").format(row[0], row[1])
+ frappe.db.commit()
+ else:
+ msg = _("Ignored: {0} to {1}").format(row[0], row[1])
+ except Exception, e:
+ msg = _("** Failed: {0} to {1}: {2}").format(row[0], row[1], repr(e))
+ frappe.db.rollback()
+
+ if via_console:
+ print msg
+ else:
+ rename_log.append(msg)
+
+ if not via_console:
+ return rename_log
diff --git a/frappe/model/utils.py b/frappe/model/utils/__init__.py
similarity index 100%
rename from frappe/model/utils.py
rename to frappe/model/utils/__init__.py
diff --git a/frappe/model/utils/rename_field.py b/frappe/model/utils/rename_field.py
new file mode 100644
index 0000000000..03b39414c3
--- /dev/null
+++ b/frappe/model/utils/rename_field.py
@@ -0,0 +1,133 @@
+# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
+# MIT License. See license.txt
+
+from __future__ import unicode_literals
+
+import frappe
+import json
+from frappe.model import no_value_fields
+
+def rename_field(doctype, old_fieldname, new_fieldname):
+ """This functions assumes that doctype is already synced"""
+
+ meta = frappe.get_meta(doctype, cached=False)
+ new_field = meta.get_field(new_fieldname)
+ if not new_field:
+ print "rename_field: " + (new_fieldname) + " not found in " + doctype
+ return
+
+ if new_field.fieldtype == "Table":
+ # change parentfield of table mentioned in options
+ frappe.db.sql("""update `tab%s` set parentfield=%s
+ where parentfield=%s""" % (new_field.options.split("\n")[0], "%s", "%s"),
+ (new_fieldname, old_fieldname))
+ elif new_field.fieldtype not in no_value_fields:
+ if meta.issingle:
+ frappe.db.sql("""update `tabSingles` set field=%s
+ where doctype=%s and field=%s""",
+ (new_fieldname, doctype, old_fieldname))
+ else:
+ # copy field value
+ frappe.db.sql("""update `tab%s` set `%s`=`%s`""" % \
+ (doctype, new_fieldname, old_fieldname))
+
+ update_reports(doctype, old_fieldname, new_fieldname)
+ update_users_report_view_settings(doctype, old_fieldname, new_fieldname)
+
+ # update in property setter
+ update_property_setters(doctype, old_fieldname, new_fieldname)
+
+def update_reports(doctype, old_fieldname, new_fieldname):
+ def _get_new_sort_by(report_dict, report, key):
+ sort_by = report_dict.get(key) or ""
+ if sort_by:
+ sort_by = sort_by.split(".")
+ if len(sort_by) > 1:
+ if sort_by[0]==doctype and sort_by[1]==old_fieldname:
+ sort_by = doctype + "." + new_fieldname
+ report_dict["updated"] = True
+ elif report.ref_doctype == doctype and sort_by[0]==old_fieldname:
+ sort_by = doctype + "." + new_fieldname
+ report_dict["updated"] = True
+
+ if isinstance(sort_by, list):
+ sort_by = '.'.join(sort_by)
+
+ return sort_by
+
+ reports = frappe.db.sql("""select name, ref_doctype, json from tabReport
+ where report_type = 'Report Builder' and ifnull(is_standard, 'No') = 'No'
+ and json like %s and json like %s""",
+ ('%%%s%%' % old_fieldname , '%%%s%%' % doctype), as_dict=True)
+
+ for r in reports:
+ report_dict = json.loads(r.json)
+
+ # update filters
+ new_filters = []
+ for f in report_dict.get("filters"):
+ if f and len(f) > 1 and f[0] == doctype and f[1] == old_fieldname:
+ new_filters.append([doctype, new_fieldname, f[2], f[3]])
+ report_dict["updated"] = True
+ else:
+ new_filters.append(f)
+
+ # update columns
+ new_columns = []
+ for c in report_dict.get("columns"):
+ if c and len(c) > 1 and c[0] == old_fieldname and c[1] == doctype:
+ new_columns.append([new_fieldname, doctype])
+ report_dict["updated"] = True
+ else:
+ new_columns.append(c)
+
+ # update sort by
+ new_sort_by = _get_new_sort_by(report_dict, r, "sort_by")
+ new_sort_by_next = _get_new_sort_by(report_dict, r, "sort_by_next")
+
+ if report_dict.get("updated"):
+ new_val = json.dumps({
+ "filters": new_filters,
+ "columns": new_columns,
+ "sort_by": new_sort_by,
+ "sort_order": report_dict.get("sort_order"),
+ "sort_by_next": new_sort_by_next,
+ "sort_order_next": report_dict.get("sort_order_next")
+ })
+
+ frappe.db.sql("""update `tabReport` set `json`=%s where name=%s""", (new_val, r.name))
+
+def update_users_report_view_settings(doctype, ref_fieldname, new_fieldname):
+ user_report_cols = frappe.db.sql("""select defkey, defvalue from `tabDefaultValue` where
+ defkey like '_list_settings:%'""")
+ for key, value in user_report_cols:
+ new_columns = []
+ columns_modified = False
+ for field, field_doctype in json.loads(value):
+ if field == ref_fieldname and field_doctype == doctype:
+ new_columns.append([new_fieldname, field_doctype])
+ columns_modified=True
+ else:
+ new_columns.append([field, field_doctype])
+
+ if columns_modified:
+ frappe.db.sql("""update `tabDefaultValue` set defvalue=%s
+ where defkey=%s""" % ('%s', '%s'), (json.dumps(new_columns), key))
+
+def update_property_setters(doctype, old_fieldname, new_fieldname):
+ frappe.db.sql("""update `tabProperty Setter` set field_name = %s
+ where doc_type=%s and field_name=%s""", (new_fieldname, doctype, old_fieldname))
+
+ idx_property = frappe.db.sql("""select name, value from `tabProperty Setter`
+ where doc_type=%s and property = '_idx' and value like '%%%s%%'""",
+ (doctype, old_fieldname), as_dict=1)
+
+ if idx_property:
+ idx_property_value = json.loads(idx_property[0].value)
+ for field in idx_property_value:
+ if field == old_fieldname:
+ field = new_fieldname
+ break
+
+ frappe.db.set_value("Property Setter", idx_property[0].name, "value", json.dumps(idx_property_value))
+
\ No newline at end of file
diff --git a/frappe/modules.txt b/frappe/modules.txt
index e435b0231c..1b8d17eb40 100644
--- a/frappe/modules.txt
+++ b/frappe/modules.txt
@@ -6,3 +6,4 @@ Custom
Geo
Desk
Print
+Integrations
\ No newline at end of file
diff --git a/frappe/modules/import_file.py b/frappe/modules/import_file.py
index 2ecad22f28..0aea4fd2ca 100644
--- a/frappe/modules/import_file.py
+++ b/frappe/modules/import_file.py
@@ -7,19 +7,19 @@ import frappe, os, json
from frappe.modules import get_module_path, scrub_dt_dn
from frappe.utils import get_datetime_str
-def import_files(module, dt=None, dn=None, force=False):
+def import_files(module, dt=None, dn=None, force=False, pre_process=None):
if type(module) is list:
out = []
for m in module:
- out.append(import_file(m[0], m[1], m[2], force=force))
+ out.append(import_file(m[0], m[1], m[2], force=force, pre_process=pre_process))
return out
else:
- return import_file(module, dt, dn, force=force)
+ return import_file(module, dt, dn, force=force, pre_process=pre_process)
-def import_file(module, dt, dn, force=False):
+def import_file(module, dt, dn, force=False, pre_process=None):
"""Sync a file from txt if modifed, return false if not updated"""
path = get_file_path(module, dt, dn)
- ret = import_file_by_path(path, force)
+ ret = import_file_by_path(path, force, pre_process=pre_process)
return ret
def get_file_path(module, dt, dn):
@@ -30,7 +30,7 @@ def get_file_path(module, dt, dn):
return path
-def import_file_by_path(path, force=False, data_import=False):
+def import_file_by_path(path, force=False, data_import=False, pre_process=None):
frappe.flags.in_import = True
try:
docs = read_doc_from_file(path)
@@ -51,7 +51,7 @@ def import_file_by_path(path, force=False, data_import=False):
original_modified = doc.get("modified")
- import_doc(doc, force=force, data_import=data_import)
+ import_doc(doc, force=force, data_import=data_import, pre_process=pre_process)
if original_modified:
# since there is a new timestamp on the file, update timestamp in
@@ -87,10 +87,12 @@ ignore_values = {
ignore_doctypes = ["Page Role", "DocPerm"]
-def import_doc(docdict, force=False, data_import=False):
+def import_doc(docdict, force=False, data_import=False, pre_process=None):
frappe.flags.in_import = True
docdict["__islocal"] = 1
doc = frappe.get_doc(docdict)
+ if pre_process:
+ pre_process(doc)
ignore = []
diff --git a/frappe/patches.txt b/frappe/patches.txt
index c306188ee8..5d0cb6f1f9 100644
--- a/frappe/patches.txt
+++ b/frappe/patches.txt
@@ -1,17 +1,25 @@
execute:frappe.db.sql("""update `tabPatch Log` set patch=replace(patch, '.4_0.', '.v4_0.')""") #2014-05-12
frappe.patches.v5_0.convert_to_barracuda_and_utf8mb4
+frappe.patches.v6_1.rename_file_data
execute:frappe.reload_doc('core', 'doctype', 'doctype', force=True) #2014-01-24
-execute:frappe.reload_doc('core', 'doctype', 'docfield', force=True) #2015-05-15
-execute:frappe.reload_doc('core', 'doctype', 'docperm') #2014-06-04
+execute:frappe.reload_doc('core', 'doctype', 'docfield', force=True) #2015-10-16
+execute:frappe.reload_doc('core', 'doctype', 'docperm') #2014-06-24
+execute:frappe.reload_doc('custom', 'doctype', 'custom_field') #2015-10-19
execute:frappe.reload_doc('core', 'doctype', 'page') #2013-13-26
execute:frappe.reload_doc('core', 'doctype', 'report') #2014-06-03
execute:frappe.reload_doc('core', 'doctype', 'version') #2014-02-21
execute:frappe.reload_doc('email', 'doctype', 'email_alert') #2014-07-15
execute:frappe.reload_doc('desk', 'doctype', 'todo') #2014-12-31-1
execute:frappe.reload_doc('custom', 'doctype', 'property_setter') #2014-12-31-1
+execute:frappe.reload_doc('core', 'doctype', 'patch_log') #2016-10-31
+execute:frappe.reload_doctype("File") # 2015-10-19
+execute:frappe.reload_doc('core', 'doctype', 'error_snapshot')
execute:frappe.db.sql("alter table `tabSessions` modify `user` varchar(255), engine=InnoDB")
execute:frappe.db.sql("delete from `tabDocField` where parent='0'")
frappe.patches.v4_0.change_varchar_length
+frappe.patches.v6_4.reduce_varchar_length
+frappe.patches.v5_2.change_checks_to_not_null
+frappe.patches.v6_9.int_float_not_null #2015-11-25
frappe.patches.v5_0.v4_to_v5
frappe.patches.v5_0.remove_shopping_cart_app
@@ -66,6 +74,7 @@ frappe.patches.v5_0.clear_website_group_and_notifications
execute:frappe.db.sql("""update tabComment set comment = substr(comment, 6, locate(":", comment)-6) where comment_type in ("Assigned", "Assignment Completed")""")
frappe.patches.v5_0.fix_feed
frappe.patches.v5_0.update_shared
+execute:frappe.reload_doc("core", "doctype", "docshare") #2015-07-21
frappe.patches.v5_0.bookmarks_to_stars
frappe.patches.v5_0.style_settings_to_website_theme
frappe.patches.v5_0.rename_ref_type_fieldnames
@@ -80,3 +89,26 @@ frappe.patches.v5_0.fix_text_editor_file_urls
execute:frappe.db.sql("update `tabComment` set comment_type='Comment' where comment_doctype='Blog Post' and ifnull(comment_type, '')=''")
frappe.patches.v5_0.modify_session
frappe.patches.v5_0.expire_old_scheduler_logs
+execute:frappe.permissions.reset_perms("DocType")
+execute:frappe.db.sql("delete from `tabProperty Setter` where `property` = 'idx'")
+frappe.patches.v5_3.rename_chinese_languages
+frappe.patches.v6_0.communication_status_and_permission
+frappe.patches.v6_0.make_task_log_folder
+frappe.patches.v6_0.document_type_rename
+frappe.patches.v6_0.fix_ghana_currency
+frappe.patches.v6_2.ignore_user_permissions_if_missing
+execute:frappe.db.sql("delete from tabSessions where user is null")
+frappe.patches.v6_2.rename_backup_manager
+execute:frappe.delete_doc("DocType", "Backup Manager")
+frappe.patches.v6_4.rename_bengali_language
+execute:frappe.db.sql("""update `tabCommunication` set parenttype=null, parent=null, parentfield=null""") #2015-10-22
+execute:frappe.permissions.reset_perms("Web Page")
+frappe.patches.v6_6.user_last_active
+frappe.patches.v6_6.rename_slovak_language
+frappe.patches.v6_6.fix_file_url
+frappe.patches.v6_9.rename_burmese_language
+frappe.patches.v6_11.rename_field_in_email_account
+execute:frappe.create_folder(os.path.join(frappe.local.site_path, 'private', 'files'))
+frappe.patches.v6_15.remove_property_setter_for_previous_field #2015-12-29
+frappe.patches.v6_15.set_username
+execute:frappe.permissions.reset_perms("Error Snapshot")
diff --git a/frappe/patches/v4_0/change_varchar_length.py b/frappe/patches/v4_0/change_varchar_length.py
index 3a62c08347..950d56316d 100644
--- a/frappe/patches/v4_0/change_varchar_length.py
+++ b/frappe/patches/v4_0/change_varchar_length.py
@@ -5,7 +5,7 @@ from __future__ import unicode_literals
import frappe
def execute():
- for dt in frappe.db.sql_list("""select name from `tabDocType` where ifnull(issingle, 0)=0"""):
+ for dt in frappe.db.sql_list("""select name from `tabDocType` where issingle=0"""):
desc = dict((d["Field"], d) for d in frappe.db.sql("desc `tab{}`".format(dt), as_dict=True))
alter_table = []
diff --git a/frappe/patches/v4_0/file_manager_hooks.py b/frappe/patches/v4_0/file_manager_hooks.py
index fe2ba0337b..2ebcf8ac04 100644
--- a/frappe/patches/v4_0/file_manager_hooks.py
+++ b/frappe/patches/v4_0/file_manager_hooks.py
@@ -12,9 +12,9 @@ from frappe.utils.file_manager import get_content_hash, get_file
def execute():
frappe.reload_doc('core', 'doctype', 'file_data')
for name, file_name, file_url in frappe.db.sql(
- """select name, file_name, file_url from `tabFile Data`
+ """select name, file_name, file_url from `tabFile`
where file_name is not null"""):
- b = frappe.get_doc('File Data', name)
+ b = frappe.get_doc('File', name)
old_file_name = b.file_name
b.file_name = os.path.basename(old_file_name)
if old_file_name.startswith('files/') or old_file_name.startswith('/files/'):
diff --git a/frappe/patches/v4_0/fix_attach_field_file_url.py b/frappe/patches/v4_0/fix_attach_field_file_url.py
index 58a2e4391d..c29e5763f1 100644
--- a/frappe/patches/v4_0/fix_attach_field_file_url.py
+++ b/frappe/patches/v4_0/fix_attach_field_file_url.py
@@ -5,8 +5,8 @@ from __future__ import unicode_literals
import frappe
def execute():
- attach_fields = (frappe.db.sql("""select parent, fieldname from `tabDocField` where fieldtype='Attach'""") +
- frappe.db.sql("""select dt, fieldname from `tabCustom Field` where fieldtype='Attach'"""))
+ attach_fields = (frappe.db.sql("""select parent, fieldname from `tabDocField` where fieldtype in ('Attach', 'Attach Image')""") +
+ frappe.db.sql("""select dt, fieldname from `tabCustom Field` where fieldtype in ('Attach', 'Attach Image')"""))
for doctype, fieldname in attach_fields:
frappe.db.sql("""update `tab{doctype}` set `{fieldname}`=concat("/", `{fieldname}`)
diff --git a/frappe/patches/v4_0/rename_profile_to_user.py b/frappe/patches/v4_0/rename_profile_to_user.py
index 85b8f53c0b..48555ead9e 100644
--- a/frappe/patches/v4_0/rename_profile_to_user.py
+++ b/frappe/patches/v4_0/rename_profile_to_user.py
@@ -1,7 +1,7 @@
from __future__ import unicode_literals
import frappe
-from frappe.model import rename_field
+from frappe.model.utils.rename_field import rename_field
from frappe.model.meta import get_table_columns
def execute():
diff --git a/frappe/patches/v4_0/rename_sitemap_to_route.py b/frappe/patches/v4_0/rename_sitemap_to_route.py
index af75763343..4deca2f052 100644
--- a/frappe/patches/v4_0/rename_sitemap_to_route.py
+++ b/frappe/patches/v4_0/rename_sitemap_to_route.py
@@ -1,7 +1,7 @@
from __future__ import unicode_literals
import frappe
-from frappe.model import rename_field
+from frappe.model.utils.rename_field import rename_field
def execute():
tables = frappe.db.sql_list("show tables")
diff --git a/frappe/patches/v4_0/set_user_permissions.py b/frappe/patches/v4_0/set_user_permissions.py
index 56c751abda..726b9ee715 100644
--- a/frappe/patches/v4_0/set_user_permissions.py
+++ b/frappe/patches/v4_0/set_user_permissions.py
@@ -10,12 +10,12 @@ def execute():
table_columns = frappe.db.get_table_columns("DocPerm")
if "restricted" in table_columns:
- frappe.db.sql("""update `tabDocPerm` set apply_user_permissions=1 where ifnull(apply_user_permissions, 0)=0
+ frappe.db.sql("""update `tabDocPerm` set apply_user_permissions=1 where apply_user_permissions=0
and restricted=1""")
if "match" in table_columns:
frappe.db.sql("""update `tabDocPerm` set apply_user_permissions=1
- where ifnull(apply_user_permissions, 0)=0 and ifnull(`match`, '')!=''""")
+ where apply_user_permissions=0 and ifnull(`match`, '')!=''""")
# change Restriction to User Permission in tabDefaultValue
frappe.db.sql("""update `tabDefaultValue` set parenttype='User Permission' where parenttype='Restriction'""")
diff --git a/frappe/patches/v4_1/file_manager_fix.py b/frappe/patches/v4_1/file_manager_fix.py
index e0846019a9..9226bbf528 100644
--- a/frappe/patches/v4_1/file_manager_fix.py
+++ b/frappe/patches/v4_1/file_manager_fix.py
@@ -18,15 +18,15 @@ from frappe.utils import get_files_path, get_site_path
# * make missing_files.txt in site dir with files that should be recovered from
# a backup from a time before version 3 migration
#
-# * Patch remaining unpatched file data records.
+# * Patch remaining unpatched File records.
def execute():
frappe.db.auto_commit_on_many_writes = True
rename_replacing_files()
for name, file_name, file_url in frappe.db.sql(
- """select name, file_name, file_url from `tabFile Data`
+ """select name, file_name, file_url from `tabFile`
where ifnull(file_name, '')!='' and ifnull(content_hash, '')=''"""):
- b = frappe.get_doc('File Data', name)
+ b = frappe.get_doc('File', name)
old_file_name = b.file_name
b.file_name = os.path.basename(old_file_name)
if old_file_name.startswith('files/') or old_file_name.startswith('/files/'):
@@ -45,8 +45,8 @@ def execute():
def get_replaced_files():
ret = []
- new_files = dict(frappe.db.sql("select name, file_name from `tabFile Data` where file_name not like 'files/%'"))
- old_files = dict(frappe.db.sql("select name, file_name from `tabFile Data` where ifnull(content_hash, '')=''"))
+ new_files = dict(frappe.db.sql("select name, file_name from `tabFile` where file_name not like 'files/%'"))
+ old_files = dict(frappe.db.sql("select name, file_name from `tabFile` where ifnull(content_hash, '')=''"))
invfiles = invert_dict(new_files)
for nname, nfilename in new_files.iteritems():
@@ -63,7 +63,7 @@ def rename_replacing_files():
for file_name, file_datas in replaced_files:
print 'processing ' + file_name
- content_hash = frappe.db.get_value('File Data', file_datas[0], 'content_hash')
+ content_hash = frappe.db.get_value('File', file_datas[0], 'content_hash')
if not content_hash:
continue
new_file_name = get_file_name(file_name, content_hash)
@@ -75,7 +75,7 @@ def rename_replacing_files():
except OSError:
print 'Error renaming ', file_name
for name in file_datas:
- f = frappe.get_doc('File Data', name)
+ f = frappe.get_doc('File', name)
f.file_name = new_file_name
f.file_url = '/files/' + new_file_name
f.save()
diff --git a/frappe/patches/v5_0/rename_table_fieldnames.py b/frappe/patches/v5_0/rename_table_fieldnames.py
index ad426ef2f6..d2564e5ab0 100644
--- a/frappe/patches/v5_0/rename_table_fieldnames.py
+++ b/frappe/patches/v5_0/rename_table_fieldnames.py
@@ -2,7 +2,7 @@
# License: GNU General Public License v3. See license.txt
import frappe
-from frappe.model import rename_field
+from frappe.model.utils.rename_field import rename_field
from frappe.modules import scrub, get_doctype_module
rename_map = {
diff --git a/frappe/patches/v5_2/__init__.py b/frappe/patches/v5_2/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/frappe/patches/v5_2/change_checks_to_not_null.py b/frappe/patches/v5_2/change_checks_to_not_null.py
new file mode 100644
index 0000000000..23f5d659b5
--- /dev/null
+++ b/frappe/patches/v5_2/change_checks_to_not_null.py
@@ -0,0 +1,34 @@
+from __future__ import unicode_literals
+import frappe
+from frappe.utils import cint
+from frappe.model import default_fields
+
+def execute():
+ for table in frappe.db.get_tables():
+ doctype = table[3:]
+ if frappe.db.exists("DocType", doctype):
+ fieldnames = [df["fieldname"] for df in
+ frappe.get_all("DocField", fields=["fieldname"], filters={"parent": doctype})]
+ custom_fieldnames = [df["fieldname"] for df in
+ frappe.get_all("Custom Field", fields=["fieldname"], filters={"dt": doctype})]
+
+ else:
+ fieldnames = custom_fieldnames = []
+
+ for column in frappe.db.sql("""desc `{0}`""".format(table), as_dict=True):
+ if column["Type"]=="int(1)":
+ fieldname = column["Field"]
+
+ # only change for defined fields, ignore old fields that don't exist in meta
+ if not (fieldname in default_fields or fieldname in fieldnames or fieldname in custom_fieldnames):
+ continue
+
+ # set 0
+ frappe.db.sql("""update `{table}` set `{column}`=0 where `{column}` is null"""\
+ .format(table=table, column=fieldname))
+ frappe.db.commit()
+
+ # change definition
+ frappe.db.sql_ddl("""alter table `{table}`
+ modify `{column}` int(1) not null default {default}"""\
+ .format(table=table, column=fieldname, default=cint(column["Default"])))
diff --git a/frappe/patches/v5_3/__init__.py b/frappe/patches/v5_3/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/frappe/patches/v5_3/rename_chinese_languages.py b/frappe/patches/v5_3/rename_chinese_languages.py
new file mode 100644
index 0000000000..8bc954c04c
--- /dev/null
+++ b/frappe/patches/v5_3/rename_chinese_languages.py
@@ -0,0 +1,13 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+import frappe
+from frappe.translate import rename_language
+
+def execute():
+ language_map = {
+ "中国(简体)": "簡體中文",
+ "中國(繁體)": "正體中文"
+ }
+
+ for old_name, new_name in language_map.items():
+ rename_language(old_name, new_name)
diff --git a/frappe/patches/v6_0/__init__.py b/frappe/patches/v6_0/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/frappe/patches/v6_0/communication_status_and_permission.py b/frappe/patches/v6_0/communication_status_and_permission.py
new file mode 100644
index 0000000000..c68ed9b4d6
--- /dev/null
+++ b/frappe/patches/v6_0/communication_status_and_permission.py
@@ -0,0 +1,19 @@
+from __future__ import unicode_literals
+import frappe
+from frappe.permissions import reset_perms
+
+def execute():
+ frappe.reload_doctype("Communication")
+
+ # set status = "Linked"
+ frappe.db.sql("""update `tabCommunication` set status='Linked'
+ where ifnull(reference_doctype, '')!='' and ifnull(reference_name, '')!=''""")
+
+ frappe.db.sql("""update `tabCommunication` set status='Closed'
+ where status='Archived'""")
+
+ # reset permissions if owner of all DocPerms is Administrator
+ if not frappe.db.sql("""select name from `tabDocPerm`
+ where parent='Communication' and ifnull(owner, '')!='Administrator'"""):
+
+ reset_perms("Communication")
diff --git a/frappe/patches/v6_0/document_type_rename.py b/frappe/patches/v6_0/document_type_rename.py
new file mode 100644
index 0000000000..0d9ca7da0e
--- /dev/null
+++ b/frappe/patches/v6_0/document_type_rename.py
@@ -0,0 +1,7 @@
+import frappe
+
+def execute():
+ frappe.db.sql("""update tabDocType set document_type='Document'
+ where document_type='Transaction'""")
+ frappe.db.sql("""update tabDocType set document_type='Setup'
+ where document_type='Master'""")
diff --git a/frappe/patches/v6_0/fix_ghana_currency.py b/frappe/patches/v6_0/fix_ghana_currency.py
new file mode 100644
index 0000000000..10365148b1
--- /dev/null
+++ b/frappe/patches/v6_0/fix_ghana_currency.py
@@ -0,0 +1,7 @@
+
+def execute():
+ from frappe.geo.country_info import get_all
+ import frappe.utils.install
+
+ countries = get_all()
+ frappe.utils.install.add_country_and_currency("Ghana", frappe._dict(countries["Ghana"]))
diff --git a/frappe/patches/v6_0/make_task_log_folder.py b/frappe/patches/v6_0/make_task_log_folder.py
new file mode 100644
index 0000000000..f557b5c8a1
--- /dev/null
+++ b/frappe/patches/v6_0/make_task_log_folder.py
@@ -0,0 +1,6 @@
+import frappe.utils, os
+
+def execute():
+ path = frappe.utils.get_site_path('task-logs')
+ if not os.path.exists(path):
+ os.makedirs(path)
diff --git a/frappe/patches/v6_1/__init__.py b/frappe/patches/v6_1/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/frappe/patches/v6_1/rename_file_data.py b/frappe/patches/v6_1/rename_file_data.py
new file mode 100644
index 0000000000..f077896dd4
--- /dev/null
+++ b/frappe/patches/v6_1/rename_file_data.py
@@ -0,0 +1,37 @@
+import frappe
+
+def execute():
+ from frappe.core.doctype.file.file import make_home_folder
+
+ if not frappe.db.exists("DocType", "File"):
+ frappe.rename_doc("DocType", "File Data", "File")
+ frappe.reload_doctype("File")
+
+ if not frappe.db.exists("File", {"is_home_folder": 1}):
+ make_home_folder()
+
+ # make missing folders and set parent folder
+ for file in frappe.get_all("File", filters={"is_folder": 0}):
+ file = frappe.get_doc("File", file.name)
+ file.flags.ignore_folder_validate = True
+ file.flags.ignore_file_validate = True
+ file.flags.ignore_duplicate_entry_error = True
+ file.flags.ignore_links = True
+ file.set_folder_name()
+ try:
+ file.save()
+ except:
+ print frappe.get_traceback()
+ raise
+
+ from frappe.utils.nestedset import rebuild_tree
+ rebuild_tree("File", "folder")
+
+ # reset file size
+ for folder in frappe.db.sql("""select name from tabFile f1 where is_folder = 1 and
+ (select count(*) from tabFile f2 where f2.folder = f1.name and f2.is_folder = 1) = 0"""):
+ folder = frappe.get_doc("File", folder[0])
+ folder.save()
+
+
+
diff --git a/frappe/patches/v6_11/__init__.py b/frappe/patches/v6_11/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/frappe/patches/v6_11/rename_field_in_email_account.py b/frappe/patches/v6_11/rename_field_in_email_account.py
new file mode 100644
index 0000000000..77549027aa
--- /dev/null
+++ b/frappe/patches/v6_11/rename_field_in_email_account.py
@@ -0,0 +1,5 @@
+import frappe
+
+def execute():
+ frappe.reload_doctype("Email Account")
+ frappe.db.sql("update `tabEmail Account` set email_server = pop3_server")
diff --git a/frappe/patches/v6_15/__init__.py b/frappe/patches/v6_15/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/frappe/patches/v6_15/remove_property_setter_for_previous_field.py b/frappe/patches/v6_15/remove_property_setter_for_previous_field.py
new file mode 100644
index 0000000000..6379bb46e2
--- /dev/null
+++ b/frappe/patches/v6_15/remove_property_setter_for_previous_field.py
@@ -0,0 +1,83 @@
+# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
+# MIT License. See license.txt
+
+from __future__ import unicode_literals
+import frappe, json
+from frappe.utils import cstr
+
+def execute():
+ frappe.db.sql("""delete from `tabProperty Setter` where property='previous_field'""")
+
+ all_custom_fields = frappe._dict()
+ for d in frappe.db.sql("""select name, dt, fieldname, insert_after from `tabCustom Field`
+ where insert_after is not null and insert_after != ''""", as_dict=1):
+ all_custom_fields.setdefault(d.dt, frappe._dict()).setdefault(d.fieldname, d.insert_after)
+
+ for dt, custom_fields in all_custom_fields.items():
+ _idx = []
+ existing_ps = frappe.db.get_value("Property Setter",
+ {"doc_type": dt, "property": "_idx"}, ["name", "value", "creation"], as_dict=1)
+
+ # if no existsing property setter, build based on meta
+ if not existing_ps:
+ _idx = get_sorted_fields(dt, custom_fields)
+ else:
+ _idx = json.loads(existing_ps.value)
+
+ idx_needs_to_be_fixed = False
+ for fieldname, insert_after in custom_fields.items():
+ # Delete existing property setter if field is not there
+ if fieldname not in _idx:
+ idx_needs_to_be_fixed = True
+ break
+ else:
+ previous_field = _idx[_idx.index(fieldname) - 1]
+
+ if previous_field != insert_after and cstr(existing_ps.creation) >= "2015-12-28":
+ idx_needs_to_be_fixed = True
+ break
+
+ if idx_needs_to_be_fixed:
+ frappe.delete_doc("Property Setter", existing_ps.name)
+ _idx = get_sorted_fields(dt, custom_fields)
+
+ if _idx:
+ frappe.make_property_setter({
+ "doctype":dt,
+ "doctype_or_field": "DocType",
+ "property": "_idx",
+ "value": json.dumps(_idx),
+ "property_type": "Text"
+ }, validate_fields_for_doctype=False)
+
+
+def get_sorted_fields(doctype, custom_fields):
+ """sort on basis of insert_after"""
+ fields_dict = frappe.get_meta(doctype).get("fields")
+
+ standard_fields_count = frappe.db.sql("""select count(name) from `tabDocField`
+ where parent=%s""", doctype)[0][0]
+
+ newlist = []
+ pending = [d.fieldname for d in fields_dict]
+
+ maxloops = len(custom_fields) + 20
+ while (pending and maxloops>0):
+ maxloops -= 1
+ for fieldname in pending[:]:
+ if fieldname in custom_fields and len(newlist) >= standard_fields_count:
+ # field already added
+ for n in newlist:
+ if n==custom_fields.get(fieldname):
+ newlist.insert(newlist.index(n)+1, fieldname)
+ pending.remove(fieldname)
+ break
+ else:
+ newlist.append(fieldname)
+ pending.remove(fieldname)
+
+ # recurring at end
+ if pending:
+ newlist += pending
+
+ return newlist
\ No newline at end of file
diff --git a/frappe/patches/v6_15/set_username.py b/frappe/patches/v6_15/set_username.py
new file mode 100644
index 0000000000..4e62cad178
--- /dev/null
+++ b/frappe/patches/v6_15/set_username.py
@@ -0,0 +1,15 @@
+import frappe
+
+def execute():
+ frappe.reload_doctype("User")
+
+ # give preference to System Users
+ users = frappe.db.sql_list("""select name from `tabUser` order by if(user_type='System User', 0, 1)""")
+ for name in users:
+ user = frappe.get_doc("User", name)
+ if user.username or not user.first_name:
+ continue
+
+ username = user.suggest_username()
+ if username:
+ user.db_set("username", username, update_modified=False)
diff --git a/frappe/patches/v6_2/__init__.py b/frappe/patches/v6_2/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/frappe/patches/v6_2/ignore_user_permissions_if_missing.py b/frappe/patches/v6_2/ignore_user_permissions_if_missing.py
new file mode 100644
index 0000000000..468f99a83d
--- /dev/null
+++ b/frappe/patches/v6_2/ignore_user_permissions_if_missing.py
@@ -0,0 +1,9 @@
+from __future__ import unicode_literals
+import frappe
+
+def execute():
+ frappe.reload_doctype("System Settings")
+ system_settings = frappe.get_doc("System Settings")
+ system_settings.ignore_user_permissions_if_missing = 1
+ system_settings.flags.ignore_mandatory = 1
+ system_settings.save()
diff --git a/frappe/patches/v6_2/rename_backup_manager.py b/frappe/patches/v6_2/rename_backup_manager.py
new file mode 100644
index 0000000000..974a4fe7d6
--- /dev/null
+++ b/frappe/patches/v6_2/rename_backup_manager.py
@@ -0,0 +1,19 @@
+import frappe
+
+def execute():
+ unset = False
+ frappe.reload_doc("integrations", "doctype", "dropbox_backup")
+
+ dropbox_backup = frappe.get_doc("Dropbox Backup", "Dropbox Backup")
+ for df in dropbox_backup.meta.fields:
+ value = frappe.db.get_single_value("Backup Manager", df.fieldname)
+ if value:
+ if df.fieldname=="upload_backups_to_dropbox" and value=="Never":
+ value = "Daily"
+ unset = True
+ dropbox_backup.set(df.fieldname, value)
+
+ if unset:
+ dropbox_backup.set("send_backups_to_dropbox", 0)
+
+ dropbox_backup.save()
diff --git a/frappe/patches/v6_4/__init__.py b/frappe/patches/v6_4/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/frappe/patches/v6_4/reduce_varchar_length.py b/frappe/patches/v6_4/reduce_varchar_length.py
new file mode 100644
index 0000000000..bb02451d9b
--- /dev/null
+++ b/frappe/patches/v6_4/reduce_varchar_length.py
@@ -0,0 +1,33 @@
+from __future__ import unicode_literals
+import frappe
+
+def execute():
+ for doctype in frappe.get_all("DocType", filters={"issingle": 0}):
+ doctype = doctype.name
+
+ for column in frappe.db.sql("desc `tab{doctype}`".format(doctype=doctype), as_dict=True):
+ fieldname = column["Field"]
+ column_type = column["Type"]
+
+ if not column_type.startswith("varchar"):
+ continue
+
+ max_length = frappe.db.sql("""select max(char_length(`{fieldname}`)) from `tab{doctype}`"""\
+ .format(fieldname=fieldname, doctype=doctype))
+
+ max_length = max_length[0][0] if max_length else None
+
+ if max_length and 140 < max_length <= 255:
+ print "setting length of '{fieldname}' in '{doctype}' as {length}".format(
+ fieldname=fieldname, doctype=doctype, length=max_length)
+
+ # create property setter for length
+ frappe.make_property_setter({
+ "doctype": doctype,
+ "fieldname": fieldname,
+ "property": "length",
+ "value": max_length,
+ "property_type": "Int"
+ })
+
+ frappe.clear_cache(doctype=doctype)
diff --git a/frappe/patches/v6_4/rename_bengali_language.py b/frappe/patches/v6_4/rename_bengali_language.py
new file mode 100644
index 0000000000..dbbcb62f8d
--- /dev/null
+++ b/frappe/patches/v6_4/rename_bengali_language.py
@@ -0,0 +1,7 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+import frappe
+from frappe.translate import rename_language
+
+def execute():
+ rename_language("বাঙালি", "বাংলা")
\ No newline at end of file
diff --git a/frappe/patches/v6_6/__init__.py b/frappe/patches/v6_6/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/frappe/patches/v6_6/fix_file_url.py b/frappe/patches/v6_6/fix_file_url.py
new file mode 100644
index 0000000000..4f8956d343
--- /dev/null
+++ b/frappe/patches/v6_6/fix_file_url.py
@@ -0,0 +1,36 @@
+from __future__ import unicode_literals
+import frappe
+from frappe.model.meta import is_single
+
+def execute():
+ """Fix old style file urls that start with files/"""
+ fix_file_urls()
+ fix_attach_field_urls()
+
+def fix_file_urls():
+ for file in frappe.db.sql_list("""select name from `tabFile` where file_url like 'files/%'"""):
+ file = frappe.get_doc("File", file)
+ file.db_set("file_url", "/" + file.file_url, update_modified=False)
+ try:
+ file.validate_file()
+ file.db_set("file_name", file.file_name, update_modified=False)
+ if not file.content_hash:
+ file.generate_content_hash()
+ file.db_set("content_hash", file.content_hash, update_modified=False)
+
+ except IOError:
+ pass
+
+def fix_attach_field_urls():
+ # taken from an old patch
+ attach_fields = (frappe.db.sql("""select parent, fieldname from `tabDocField` where fieldtype in ('Attach', 'Attach Image')""") +
+ frappe.db.sql("""select dt, fieldname from `tabCustom Field` where fieldtype in ('Attach', 'Attach Image')"""))
+
+ for doctype, fieldname in attach_fields:
+ if is_single(doctype):
+ frappe.db.sql("""update `tabSingles` set value=concat("/", `value`)
+ where doctype=%(doctype)s and field=%(fieldname)s
+ and value like 'files/%%'""", {"doctype": doctype, "fieldname": fieldname})
+ else:
+ frappe.db.sql("""update `tab{doctype}` set `{fieldname}`=concat("/", `{fieldname}`)
+ where `{fieldname}` like 'files/%'""".format(doctype=doctype, fieldname=fieldname))
diff --git a/frappe/patches/v6_6/rename_slovak_language.py b/frappe/patches/v6_6/rename_slovak_language.py
new file mode 100644
index 0000000000..a942543372
--- /dev/null
+++ b/frappe/patches/v6_6/rename_slovak_language.py
@@ -0,0 +1,7 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+import frappe
+from frappe.translate import rename_language
+
+def execute():
+ rename_language("slovenčina", "slovenčina (Slovak)")
diff --git a/frappe/patches/v6_6/user_last_active.py b/frappe/patches/v6_6/user_last_active.py
new file mode 100644
index 0000000000..fd55935174
--- /dev/null
+++ b/frappe/patches/v6_6/user_last_active.py
@@ -0,0 +1,6 @@
+from __future__ import unicode_literals
+import frappe
+
+def execute():
+ frappe.reload_doctype("User")
+ frappe.db.sql("update `tabUser` set last_active=last_login")
diff --git a/frappe/patches/v6_9/__init__.py b/frappe/patches/v6_9/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/frappe/patches/v6_9/int_float_not_null.py b/frappe/patches/v6_9/int_float_not_null.py
new file mode 100644
index 0000000000..97495f9077
--- /dev/null
+++ b/frappe/patches/v6_9/int_float_not_null.py
@@ -0,0 +1,30 @@
+from __future__ import unicode_literals
+import frappe
+from frappe.utils import cint, flt
+
+def execute():
+ for doctype in frappe.get_all("DocType", filters={"issingle": 0}):
+ doctype = doctype.name
+ meta = frappe.get_meta(doctype)
+
+ for column in frappe.db.sql("desc `tab{doctype}`".format(doctype=doctype), as_dict=True):
+ fieldname = column["Field"]
+ column_type = column["Type"]
+
+ if not (column_type.startswith("int") or column_type.startswith("decimal")):
+ continue
+
+ frappe.db.sql("""update `tab{doctype}` set `{fieldname}`=0 where `{fieldname}` is null"""\
+ .format(doctype=doctype, fieldname=fieldname))
+
+ # alter table
+ if column["Null"]=='YES':
+ if not meta.get_field(fieldname):
+ continue
+
+ default = cint(column["Default"]) if column_type.startswith("int") else flt(column["Default"])
+ frappe.db.sql_ddl("""alter table `tab{doctype}`
+ change `{fieldname}` `{fieldname}` {column_type} not null default '{default}'""".format(
+ doctype=doctype, fieldname=fieldname, column_type=column_type, default=default))
+
+
diff --git a/frappe/patches/v6_9/rename_burmese_language.py b/frappe/patches/v6_9/rename_burmese_language.py
new file mode 100644
index 0000000000..66477f7efe
--- /dev/null
+++ b/frappe/patches/v6_9/rename_burmese_language.py
@@ -0,0 +1,7 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+import frappe
+from frappe.translate import rename_language
+
+def execute():
+ rename_language("Melayu", "မြန်မာ")
diff --git a/frappe/permissions.py b/frappe/permissions.py
index 690ea63ff8..d6a1cdf686 100644
--- a/frappe/permissions.py
+++ b/frappe/permissions.py
@@ -17,7 +17,11 @@ def check_admin_or_system_manager(user=None):
frappe.throw(_("Not permitted"), frappe.PermissionError)
def has_permission(doctype, ptype="read", doc=None, verbose=False, user=None):
- """check if user has permission"""
+ """Returns True if user has permission `ptype` for given `doctype`.
+ If `doc` is passed, it also checks user, share and owner permissions.
+
+ Note: if Table DocType is passed, it always returns True.
+ """
if not user: user = frappe.session.user
if frappe.is_table(doctype):
@@ -40,19 +44,24 @@ def has_permission(doctype, ptype="read", doc=None, verbose=False, user=None):
def false_if_not_shared():
if ptype in ("read", "write", "share", "email", "print"):
- shared = frappe.share.get_shared(doctype, user,
+ shared = frappe.share.get_shared(doctype, user,
["read" if ptype in ("email", "print") else ptype])
+
if doc:
doc_name = doc if isinstance(doc, basestring) else doc.name
if doc_name in shared:
if verbose: print "Shared"
if ptype in ("read", "write", "share") or meta.permissions[0].get(ptype):
+ if verbose: print "Is shared"
return True
-
- else:
+
+ elif shared:
+ # if atleast one shared doc of that type, then return True
+ # this is used in db_query to check if permission on DocType
if verbose: print "Has a shared document"
return True
+ if verbose: print "Not Shared"
return False
role_permissions = get_role_permissions(meta, user=user, verbose=verbose)
@@ -60,25 +69,43 @@ def has_permission(doctype, ptype="read", doc=None, verbose=False, user=None):
if not role_permissions.get(ptype):
return false_if_not_shared()
+ perm = True
+
if doc:
if isinstance(doc, basestring):
doc = frappe.get_doc(meta.name, doc)
- if role_permissions["apply_user_permissions"].get(ptype):
- if not user_has_permission(doc, verbose=verbose, user=user,
- user_permission_doctypes=role_permissions.get("user_permission_doctypes", {}).get(ptype) or []):
- if verbose: print "No user permission"
- return false_if_not_shared()
+ owner_perm = user_perm = controller_perm = None
- if not has_controller_permissions(doc, ptype, user=user):
- if verbose: print "No controller permission"
- return false_if_not_shared()
+ if role_permissions["if_owner"].get(ptype) and ptype!="create":
+ owner_perm = doc.owner == frappe.session.user
+ if verbose: print "Owner permission: {0}".format(owner_perm)
- if verbose:
- print "Has Role"
- return True
+ # check if user permission
+ if not owner_perm and role_permissions["apply_user_permissions"].get(ptype):
+ user_perm = user_has_permission(doc, verbose=verbose, user=user,
+ user_permission_doctypes=role_permissions.get("user_permission_doctypes", {}).get(ptype) or [])
+
+ if verbose: print "User permission: {0}".format(user_perm)
+
+ if not owner_perm and not user_perm:
+ controller_perm = has_controller_permissions(doc, ptype, user=user)
+
+ if verbose: print "Controller permission: {0}".format(controller_perm)
+
+ # permission true if any one condition is explicitly True or all permissions are undefined (None)
+ perm = any([owner_perm, user_perm, controller_perm]) or \
+ all([owner_perm==None, user_perm==None, controller_perm==None])
+
+ if not perm:
+ perm = false_if_not_shared()
+
+ if verbose: print "Final Permission: {0}".format(perm)
+
+ return perm
def get_doc_permissions(doc, verbose=False, user=None):
+ """Returns a dict of evaluated permissions for given `doc` like `{"read":1, "write":1}`"""
if not user: user = frappe.session.user
if frappe.is_table(doc.doctype):
@@ -101,44 +128,112 @@ def get_doc_permissions(doc, verbose=False, user=None):
user_permission_doctypes=role_permissions.get("user_permission_doctypes", {}).get(ptype) or []):
role_permissions[ptype] = 0
- # update share permissions
- role_permissions.update(frappe.db.get_value("DocShare",
- {"share_doctype": doc.doctype, "share_name": doc.name, "user": user},
- ["read", "write", "share"], as_dict=True) or {})
+ # apply owner permissions on top of existing permissions
+ if doc.owner == frappe.session.user:
+ role_permissions.update(role_permissions.if_owner)
+
+ update_share_permissions(role_permissions, doc, user)
return role_permissions
+def update_share_permissions(role_permissions, doc, user):
+ """Updates share permissions on `role_permissions` for given doc, if shared"""
+ share_ptypes = ("read", "write", "share")
+ permissions_by_share = frappe.db.get_value("DocShare",
+ {"share_doctype": doc.doctype, "share_name": doc.name, "user": user},
+ share_ptypes, as_dict=True)
+
+ if permissions_by_share:
+ for ptype in share_ptypes:
+ if permissions_by_share[ptype]:
+ role_permissions[ptype] = 1
+
def get_role_permissions(meta, user=None, verbose=False):
+ """Returns dict of evaluated role permissions like `{"read": True, "write":False}`
+
+ If user permissions are applicable, it adds a dict of user permissions like
+
+ {
+ // user permissions will apply on these rights
+ "apply_user_permissions": {"read": 1, "write": 1},
+
+ // doctypes that will be applicable for each right
+ "user_permission_doctypes": {
+ "read": [
+ // AND between "DocType 1" and "DocType 2"
+ ["DocType 1", "DocType 2"],
+
+ // OR
+
+ ["DocType 3"]
+
+ ]
+ }
+
+ "if_owner": {"read": 1, "write": 1}
+ }
+ """
if not user: user = frappe.session.user
cache_key = (meta.name, user)
if not frappe.local.role_permissions.get(cache_key):
- perms = frappe._dict({ "apply_user_permissions": {}, "user_permission_doctypes": {} })
+ perms = frappe._dict({ "apply_user_permissions": {}, "user_permission_doctypes": {}, "if_owner": {} })
user_roles = frappe.get_roles(user)
+ dont_match = []
+ has_a_role_with_apply_user_permissions = False
for p in meta.permissions:
if cint(p.permlevel)==0 and (p.role in user_roles):
+ # apply only for level 0
+
for ptype in rights:
+ # build if_owner dict if applicable for this right
perms[ptype] = perms.get(ptype, 0) or cint(p.get(ptype))
if ptype != "set_user_permissions" and p.get(ptype):
perms["apply_user_permissions"][ptype] = (perms["apply_user_permissions"].get(ptype, 1)
and p.get("apply_user_permissions"))
+ if p.if_owner and p.get(ptype):
+ perms["if_owner"][ptype] = 1
+
+ if p.get(ptype) and not p.if_owner and not p.get("apply_user_permissions"):
+ dont_match.append(ptype)
+
if p.apply_user_permissions:
+ has_a_role_with_apply_user_permissions = True
+
if p.user_permission_doctypes:
# set user_permission_doctypes in perms
user_permission_doctypes = json.loads(p.user_permission_doctypes)
-
- if user_permission_doctypes:
- # perms["user_permission_doctypes"][ptype] would be a list of list like [["User", "Blog Post"], ["User"]]
- for ptype in rights:
- if p.get(ptype):
- perms["user_permission_doctypes"].setdefault(ptype, []).append(user_permission_doctypes)
else:
user_permission_doctypes = get_linked_doctypes(meta.name)
+ if user_permission_doctypes:
+ # perms["user_permission_doctypes"][ptype] would be a list of list like [["User", "Blog Post"], ["User"]]
+ for ptype in rights:
+ if p.get(ptype):
+ perms["user_permission_doctypes"].setdefault(ptype, []).append(user_permission_doctypes)
+ # if atleast one record having both Apply User Permission and If Owner unchecked is found,
+ # don't match for those rights
+ for ptype in rights:
+ if ptype in dont_match:
+ if perms["apply_user_permissions"].get(ptype):
+ del perms["apply_user_permissions"][ptype]
+
+ if perms["if_owner"].get(ptype):
+ del perms["if_owner"][ptype]
+
+ # if one row has only "Apply User Permissions" checked and another has only "If Owner" checked,
+ # set Apply User Permissions as checked
+ # i.e. the case when there is a role with apply_user_permissions as 1, but resultant apply_user_permissions is 0
+ if has_a_role_with_apply_user_permissions:
+ for ptype in rights:
+ if perms["if_owner"].get(ptype) and perms["apply_user_permissions"].get(ptype)==0:
+ perms["apply_user_permissions"][ptype] = 1
+
+ # delete 0 values
for key, value in perms.get("apply_user_permissions").items():
if not value:
del perms["apply_user_permissions"][key]
@@ -163,8 +258,8 @@ def user_has_permission(doc, verbose=True, user=None, user_permission_doctypes=N
result = True
for df in meta.get_fields_to_check_permissions(doctypes):
- if (df.options in user_permissions and d.get(df.fieldname)
- and d.get(df.fieldname) not in user_permissions[df.options]):
+ if (d.get(df.fieldname)
+ and d.get(df.fieldname) not in user_permissions.get(df.options, [])):
result = False
if verbose:
@@ -190,9 +285,15 @@ def user_has_permission(doc, verbose=True, user=None, user_permission_doctypes=N
return _user_has_permission
def has_controller_permissions(doc, ptype, user=None):
+ """Returns controller permissions if defined. None if not defined"""
if not user: user = frappe.session.user
- for method in frappe.get_hooks("has_permission").get(doc.doctype, []):
+ methods = frappe.get_hooks("has_permission").get(doc.doctype, [])
+
+ if not methods:
+ return None
+
+ for method in methods:
if not frappe.call(frappe.get_attr(method), doc=doc, ptype=ptype, user=user):
return False
@@ -258,14 +359,11 @@ def apply_user_permissions(doctype, ptype, user=None):
def get_user_permission_doctypes(user_permission_doctypes, user_permissions):
"""returns a list of list like [["User", "Blog Post"], ["User"]]"""
- if user_permission_doctypes:
+ if cint(frappe.db.get_single_value("System Settings", "ignore_user_permissions_if_missing")):
# select those user permission doctypes for which user permissions exist!
user_permission_doctypes = [list(set(doctypes).intersection(set(user_permissions.keys())))
for doctypes in user_permission_doctypes]
- else:
- user_permission_doctypes = [user_permissions.keys()]
-
if len(user_permission_doctypes) > 1:
# OPTIMIZATION
# if intersection exists, use that to reduce the amount of querying
diff --git a/frappe/print/doctype/letter_head/letter_head.json b/frappe/print/doctype/letter_head/letter_head.json
index 4c14cc25cb..9c730d36bf 100644
--- a/frappe/print/doctype/letter_head/letter_head.json
+++ b/frappe/print/doctype/letter_head/letter_head.json
@@ -1,86 +1,172 @@
{
+ "allow_copy": 0,
+ "allow_import": 0,
"allow_rename": 1,
"autoname": "field:letter_head_name",
"creation": "2012-11-22 17:45:46",
+ "custom": 0,
"docstatus": 0,
"doctype": "DocType",
"fields": [
{
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"fieldname": "letter_head_name",
"fieldtype": "Data",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Letter Head Name",
+ "length": 0,
+ "no_copy": 0,
"oldfieldname": "letter_head_name",
"oldfieldtype": "Data",
"permlevel": 0,
- "reqd": 1
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
},
{
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"depends_on": "letter_head_name",
"fieldname": "disabled",
"fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
"in_list_view": 1,
"label": "Disabled",
+ "length": 0,
+ "no_copy": 0,
"oldfieldname": "disabled",
"oldfieldtype": "Check",
- "permlevel": 0
+ "permlevel": 0,
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
},
{
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"depends_on": "letter_head_name",
"description": "Check this to make this the default letter head in all prints",
"fieldname": "is_default",
"fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
"in_list_view": 1,
"label": "Is Default",
+ "length": 0,
+ "no_copy": 0,
"oldfieldname": "is_default",
"oldfieldtype": "Check",
"permlevel": 0,
- "search_index": 1
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 1,
+ "set_only_once": 0,
+ "unique": 0
},
{
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"depends_on": "letter_head_name",
"description": "Letter Head in HTML",
"fieldname": "content",
"fieldtype": "Text Editor",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
"in_list_view": 1,
"label": "Content",
+ "length": 0,
+ "no_copy": 0,
"oldfieldname": "content",
"oldfieldtype": "Text Editor",
- "permlevel": 0
+ "permlevel": 0,
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
}
],
+ "hide_heading": 0,
+ "hide_toolbar": 0,
"icon": "icon-font",
"idx": 1,
+ "in_create": 0,
+ "in_dialog": 0,
+ "is_submittable": 0,
+ "issingle": 0,
+ "istable": 0,
"max_attachments": 3,
- "modified": "2015-02-05 05:11:40.906941",
+ "modified": "2015-11-16 06:29:49.706229",
"modified_by": "Administrator",
"module": "Print",
"name": "Letter Head",
"owner": "Administrator",
"permissions": [
{
+ "amend": 0,
+ "apply_user_permissions": 0,
+ "cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
+ "export": 0,
+ "if_owner": 0,
+ "import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
+ "set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
},
{
- "apply_user_permissions": 1,
+ "amend": 0,
+ "apply_user_permissions": 0,
+ "cancel": 0,
+ "create": 0,
"delete": 0,
"email": 0,
+ "export": 0,
+ "if_owner": 0,
+ "import": 0,
"permlevel": 0,
"print": 0,
"read": 1,
"report": 0,
- "role": "All"
+ "role": "All",
+ "set_user_permissions": 0,
+ "share": 0,
+ "submit": 0,
+ "write": 0
}
- ]
+ ],
+ "read_only": 0,
+ "read_only_onload": 0
}
\ No newline at end of file
diff --git a/frappe/print/doctype/print_format/print_format.js b/frappe/print/doctype/print_format/print_format.js
index 0b8b5a4f6a..e6a99f146f 100644
--- a/frappe/print/doctype/print_format/print_format.js
+++ b/frappe/print/doctype/print_format/print_format.js
@@ -13,6 +13,17 @@ frappe.ui.form.on("Print Format", "refresh", function(frm) {
if(frm.doc.standard==="Yes" && user !== "Administrator") {
frm.set_intro(__("Please duplicate this to make changes"));
}
+
+ if(!frm.is_new()) {
+ frm.add_custom_button(__("Make Default"), function() {
+ frappe.call({
+ method: "frappe.print.doctype.print_format.print_format.make_default",
+ args: {
+ name: frm.doc.name
+ }
+ })
+ })
+ }
});
frappe.ui.form.on("Print Format", "edit_format", function(frm) {
diff --git a/frappe/print/doctype/print_format/print_format.json b/frappe/print/doctype/print_format/print_format.json
index 73f426fa83..f980eaa18f 100644
--- a/frappe/print/doctype/print_format/print_format.json
+++ b/frappe/print/doctype/print_format/print_format.json
@@ -1,45 +1,93 @@
{
"allow_copy": 0,
+ "allow_import": 0,
"allow_rename": 1,
"autoname": "Prompt",
"creation": "2013-01-23 19:54:43",
+ "custom": 0,
"docstatus": 0,
"doctype": "DocType",
"fields": [
{
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"description": "",
"fieldname": "doc_type",
"fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
"in_filter": 1,
"in_list_view": 1,
"label": "DocType",
+ "length": 0,
+ "no_copy": 0,
"options": "DocType",
"permlevel": 0,
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
"reqd": 1,
- "search_index": 0
- },
- {
- "depends_on": "eval:!doc.custom_format",
- "fieldname": "edit_format",
- "fieldtype": "Button",
- "label": "Edit Format",
- "permlevel": 0,
- "precision": ""
- },
- {
- "fieldname": "column_break_3",
- "fieldtype": "Column Break",
- "permlevel": 0
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
},
{
"allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "fieldname": "disabled",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Disabled",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "fieldname": "column_break_3",
+ "fieldtype": "Column Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"default": "No",
"fieldname": "standard",
"fieldtype": "Select",
"hidden": 0,
+ "ignore_user_permissions": 0,
"in_filter": 1,
"in_list_view": 0,
"label": "Standard",
+ "length": 0,
"no_copy": 1,
"oldfieldname": "standard",
"oldfieldtype": "Select",
@@ -49,80 +97,363 @@
"read_only": 0,
"report_hide": 0,
"reqd": 1,
- "search_index": 1
- },
- {
- "fieldname": "disabled",
- "fieldtype": "Check",
- "label": "Disabled",
- "permlevel": 0
- },
- {
- "fieldname": "section_break_6",
- "fieldtype": "Section Break",
- "permlevel": 0
+ "search_index": 1,
+ "set_only_once": 0,
+ "unique": 0
},
{
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"fieldname": "custom_format",
"fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
"label": "Custom Format",
+ "length": 0,
+ "no_copy": 0,
"permlevel": 0,
- "precision": ""
+ "precision": "",
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
},
{
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "depends_on": "custom_format",
+ "fieldname": "section_break_6",
+ "fieldtype": "Section Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"default": "Server",
"depends_on": "custom_format",
"description": "",
"fieldname": "print_format_type",
"fieldtype": "Select",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
"in_list_view": 0,
"label": "Print Format Type",
+ "length": 0,
+ "no_copy": 0,
"options": "Server\nClient",
"permlevel": 0,
- "read_only": 0
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
},
{
"allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"depends_on": "custom_format",
"fieldname": "html",
"fieldtype": "Code",
"hidden": 0,
+ "ignore_user_permissions": 0,
"in_filter": 0,
+ "in_list_view": 0,
"label": "HTML",
+ "length": 0,
"no_copy": 0,
"oldfieldname": "html",
"oldfieldtype": "Text Editor",
"options": "HTML",
"permlevel": 0,
"print_hide": 0,
+ "read_only": 0,
"report_hide": 0,
"reqd": 0,
- "search_index": 0
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
},
{
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "depends_on": "eval:!doc.custom_format",
+ "fieldname": "section_break_9",
+ "fieldtype": "Section Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "depends_on": "eval:!doc.custom_format",
+ "fieldname": "edit_format",
+ "fieldtype": "Button",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Edit Format",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "fieldname": "column_break_11",
+ "fieldtype": "Column Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "default": "Default",
+ "depends_on": "eval:!doc.custom_format",
+ "fieldname": "font",
+ "fieldtype": "Select",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Font",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Default\nArial\nHelvetica\nVerdana\nMonospace",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "fieldname": "css_section",
+ "fieldtype": "Section Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "fieldname": "css",
+ "fieldtype": "Code",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Custom CSS",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "fieldname": "custom_html_help",
+ "fieldtype": "HTML",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Custom HTML Help",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Custom CSS Help \n\nNotes:
\n\n\nAll field groups (label + value) are set attributes data-fieldtype and data-fieldname \nAll values are given class value \nAll Section Breaks are given class section-break \nAll Column Breaks are given class column-break \n \n\nExamples \n\n1. Left align integers
\n\n[data-fieldtype=\"Int\"] .value { text-left: left; } \n\n1. Add border to sections except the last section
\n\n.section-break { padding: 30px 0px; border-bottom: 1px solid #eee; }\n.section-break:last-child { padding-bottom: 0px; border-bottom: 0px; } \n",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "depends_on": "custom_format",
+ "fieldname": "section_break_13",
+ "fieldtype": "Section Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"depends_on": "custom_format",
"fieldname": "print_format_help",
"fieldtype": "HTML",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
"label": "Print Format Help",
+ "length": 0,
+ "no_copy": 0,
"options": "Print Format Help \n \nIntroduction \nPrint itemsFormats are rendered on the server side using the Jinja Templating Language. All forms have access to the doc object which contains information about the document that is being formatted. You can also access common utilities via the frappe module.
\nFor styling, the Boostrap CSS framework is provided and you can enjoy the full range of classes.
\n \nReferences \n\n\tJinja Tempalting Language: Reference \n\tBootstrap CSS Framework \n \n \nExample \n<h3>{{ doc.select_print_heading or \"Invoice\" }}</h3>\n<div class=\"row\">\n\t<div class=\"col-md-3 text-right\">Customer Name</div>\n\t<div class=\"col-md-9\">{{ doc.customer_name }}</div>\n</div>\n<div class=\"row\">\n\t<div class=\"col-md-3 text-right\">Date</div>\n\t<div class=\"col-md-9\">{{ doc.get_formatted(\"invoice_date\") }}</div>\n</div>\n<table class=\"table table-bordered\">\n\t<tbody>\n\t\t<tr>\n\t\t\t<th>Sr</th>\n\t\t\t<th>Item Name</th>\n\t\t\t<th>Description</th>\n\t\t\t<th class=\"text-right\">Qty</th>\n\t\t\t<th class=\"text-right\">Rate</th>\n\t\t\t<th class=\"text-right\">Amount</th>\n\t\t</tr>\n\t\t{%- for row in doc.items -%}\n\t\t<tr>\n\t\t\t<td style=\"width: 3%;\">{{ row.idx }}</td>\n\t\t\t<td style=\"width: 20%;\">\n\t\t\t\t{{ row.item_name }}\n\t\t\t\t{% if row.item_code != row.item_name -%}\n\t\t\t\t<br>Item Code: {{ row.item_code}}\n\t\t\t\t{%- endif %}\n\t\t\t</td>\n\t\t\t<td style=\"width: 37%;\">\n\t\t\t\t<div style=\"border: 0px;\">{{ row.description }}</div></td>\n\t\t\t<td style=\"width: 10%; text-align: right;\">{{ row.qty }} {{ row.uom or row.stock_uom }}</td>\n\t\t\t<td style=\"width: 15%; text-align: right;\">{{\n\t\t\t\trow.get_formatted(\"rate\", doc) }}</td>\n\t\t\t<td style=\"width: 15%; text-align: right;\">{{\n\t\t\t\trow.get_formatted(\"amount\", doc) }}</td>\n\t\t</tr>\n\t\t{%- endfor -%}\n\t</tbody>\n</table> \n \nCommon Functions \n\n\t\n\t\t\n\t\t\tdoc.get_formatted(\"[fieldname]\", [parent_doc]) \n\t\t\tGet document value formatted as Date, Currency etc. Pass parent doc for curreny type fields. \n\t\t \n\t\t\n\t\t\tfrappe.db.get_value(\"[doctype]\", \"[name]\", \"fieldname\") \n\t\t\tGet value from another document. \n\t\t \n\t \n
\n",
- "permlevel": 0
+ "permlevel": 0,
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
},
{
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"fieldname": "format_data",
"fieldtype": "Code",
"hidden": 1,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
"label": "Format Data",
+ "length": 0,
+ "no_copy": 0,
"permlevel": 0,
"precision": "",
- "read_only": 0
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
},
{
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"fieldname": "print_format_builder",
"fieldtype": "Check",
"hidden": 1,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
"label": "Print Format Builder",
+ "length": 0,
+ "no_copy": 0,
"permlevel": 0,
- "precision": ""
+ "precision": "",
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
}
],
"hide_heading": 0,
@@ -131,10 +462,11 @@
"idx": 1,
"in_create": 0,
"in_dialog": 0,
+ "is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2015-02-05 05:11:42.667447",
+ "modified": "2015-11-16 06:29:52.109293",
"modified_by": "Administrator",
"module": "Print",
"name": "Print Format",
@@ -142,15 +474,20 @@
"permissions": [
{
"amend": 0,
+ "apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
+ "export": 0,
+ "if_owner": 0,
+ "import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
+ "set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
diff --git a/frappe/print/doctype/print_format/print_format.py b/frappe/print/doctype/print_format/print_format.py
index 583ce166a4..4a513dc694 100644
--- a/frappe/print/doctype/print_format/print_format.py
+++ b/frappe/print/doctype/print_format/print_format.py
@@ -60,3 +60,25 @@ class PrintFormat(Document):
if self.doc_type:
frappe.clear_cache(doctype=self.doc_type)
+@frappe.whitelist()
+def make_default(name):
+ """Set print format as default"""
+ frappe.has_permission("Print Format", "write")
+
+ print_format = frappe.get_doc("Print Format", name)
+
+ if (frappe.conf.get('developer_mode') or 0) == 1:
+ # developer mode, set it default in doctype
+ doctype = frappe.get_doc("DocType", print_format.doc_type)
+ doctype.default_print_format = name
+ doctype.save()
+ else:
+ # customization
+ frappe.make_property_setter({
+ 'doctype_or_field': "DocType",
+ 'doctype': print_format.doc_type,
+ 'property': "default_print_format",
+ 'value': name,
+ })
+
+ frappe.msgprint(frappe._("Done"))
diff --git a/frappe/print/doctype/print_format/test_print_format.py b/frappe/print/doctype/print_format/test_print_format.py
index 936e06402c..aa8c79200d 100644
--- a/frappe/print/doctype/print_format/test_print_format.py
+++ b/frappe/print/doctype/print_format/test_print_format.py
@@ -12,7 +12,7 @@ class TestPrintFormat(unittest.TestCase):
def test_print_user(self, style=None):
print_html = frappe.get_print("User", "Administrator", style=style)
self.assertTrue("First Name " in print_html)
- self.assertTrue(re.findall('[\s]*Administrator[\s]*
', print_html))
+ self.assertTrue(re.findall('[\s]*Administrator[\s]*
', print_html))
return print_html
def test_print_user_standard(self):
diff --git a/frappe/print/doctype/print_settings/print_settings.json b/frappe/print/doctype/print_settings/print_settings.json
index f549593eb2..324628b96e 100644
--- a/frappe/print/doctype/print_settings/print_settings.json
+++ b/frappe/print/doctype/print_settings/print_settings.json
@@ -1,82 +1,264 @@
{
+ "allow_copy": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
"creation": "2014-07-17 06:54:20.782907",
+ "custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "System",
"fields": [
{
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"fieldname": "pdf_settings",
"fieldtype": "Section Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
"label": "PDF Settings",
- "permlevel": 0
+ "no_copy": 0,
+ "permlevel": 0,
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
},
{
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"default": "1",
"description": "Send Email Print Attachments as PDF (Recommended)",
"fieldname": "send_print_as_pdf",
"fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
"label": "Send Print as PDF",
- "permlevel": 0
+ "no_copy": 0,
+ "permlevel": 0,
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
},
{
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"default": "A4",
"fieldname": "pdf_page_size",
"fieldtype": "Select",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
"label": "PDF Page Size",
+ "no_copy": 0,
"options": "A4\nLetter",
- "permlevel": 0
+ "permlevel": 0,
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
},
{
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"fieldname": "print_style_section",
"fieldtype": "Section Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
"label": "Print Style",
- "permlevel": 0
+ "no_copy": 0,
+ "permlevel": 0,
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
},
{
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"default": "Modern",
"fieldname": "print_style",
"fieldtype": "Select",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
"in_list_view": 1,
"label": "Print Style",
+ "no_copy": 0,
"options": "Modern\nClassic\nStandard\nMonochrome",
- "permlevel": 0
+ "permlevel": 0,
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
},
{
- "fieldname": "column_break_6",
- "fieldtype": "Column Break",
- "permlevel": 0
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "default": "Default",
+ "fieldname": "font",
+ "fieldtype": "Select",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Font",
+ "no_copy": 0,
+ "options": "Default\nArial\nHelvetica\nVerdana\nMonospace",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
},
{
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"description": "In points. Default is 9.",
"fieldname": "font_size",
"fieldtype": "Float",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
"label": "Font Size",
- "permlevel": 0
+ "no_copy": 0,
+ "permlevel": 0,
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
},
{
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "fieldname": "column_break_6",
+ "fieldtype": "Column Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"default": "1",
"description": "Print with Letterhead, unless unchecked in a particular Document",
"fieldname": "with_letterhead",
"fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
"label": "With Letterhead",
+ "no_copy": 0,
"permlevel": 0,
- "reqd": 0
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
},
{
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"fieldname": "section_break_8",
"fieldtype": "Section Break",
- "permlevel": 0
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
},
{
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"fieldname": "print_style_preview",
"fieldtype": "HTML",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
"label": "Print Style Preview",
- "permlevel": 0
+ "no_copy": 0,
+ "permlevel": 0,
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
}
],
+ "hide_heading": 0,
+ "hide_toolbar": 0,
"icon": "icon-cog",
+ "in_create": 0,
+ "in_dialog": 0,
+ "is_submittable": 0,
"issingle": 1,
- "modified": "2015-03-25 07:10:38.893958",
+ "istable": 0,
+ "modified": "2015-07-15 08:03:23.743143",
"modified_by": "Administrator",
"module": "Print",
"name": "Print Settings",
@@ -84,14 +266,28 @@
"owner": "Administrator",
"permissions": [
{
+ "amend": 0,
+ "apply_user_permissions": 0,
+ "cancel": 0,
"create": 1,
+ "delete": 0,
+ "email": 0,
+ "export": 0,
+ "if_owner": 0,
+ "import": 0,
"permlevel": 0,
+ "print": 0,
"read": 1,
+ "report": 0,
"role": "System Manager",
+ "set_user_permissions": 0,
"share": 1,
+ "submit": 0,
"write": 1
}
],
+ "read_only": 0,
+ "read_only_onload": 0,
"sort_field": "modified",
"sort_order": "DESC"
}
\ No newline at end of file
diff --git a/frappe/print/page/print_format_builder/print_format_builder.js b/frappe/print/page/print_format_builder/print_format_builder.js
index ce1c2c3a6c..89d5b722bb 100644
--- a/frappe/print/page/print_format_builder/print_format_builder.js
+++ b/frappe/print/page/print_format_builder/print_format_builder.js
@@ -152,6 +152,7 @@ frappe.PrintFormatBuilder = Class.extend({
me.page.set_primary_action(__("Save"), function() {
me.save_print_format();
});
+ me.page.clear_menu();
me.page.add_menu_item(__("Start new Format"), function() {
me.print_format = null;
me.refresh();
@@ -274,18 +275,21 @@ frappe.PrintFormatBuilder = Class.extend({
// visible_columns
var me = this;
if(!f.visible_columns) {
- f.visible_columns = []
- $.each(frappe.get_meta(f.options).fields, function(i, _f) {
- if(!in_list(["Section Break", "Column Break"], _f.fieldtype) &&
- !_f.print_hide && f.label) {
-
- // column names set as fieldname|width
- f.visible_columns.push({fieldname: _f.fieldname,
- print_width: (_f.width || ""), print_hide:0});
- }
- });
+ me.init_visible_columns(f);
}
},
+ init_visible_columns: function(f) {
+ f.visible_columns = []
+ $.each(frappe.get_meta(f.options).fields, function(i, _f) {
+ if(!in_list(["Section Break", "Column Break"], _f.fieldtype) &&
+ !_f.print_hide && f.label) {
+
+ // column names set as fieldname|width
+ f.visible_columns.push({fieldname: _f.fieldname,
+ print_width: (_f.width || ""), print_hide:0});
+ }
+ });
+ },
setup_sortable: function() {
var me = this;
@@ -479,10 +483,33 @@ frappe.PrintFormatBuilder = Class.extend({
});
var $body = $(d.body);
-
+
+
+ var doc_fields = frappe.get_meta(doctype).fields;
+ var docfields_by_name = {};
+
+ // docfields by fieldname
+ $.each(doc_fields, function(j, f) {
+ if(f) docfields_by_name[f.fieldname] = f;
+ })
+
+ // add field which are in column_names first to preserve order
+ var fields = [];
+ $.each(column_names, function(i, v) {
+ if(in_list(Object.keys(docfields_by_name), v)) {
+ fields.push(docfields_by_name[v]);
+ }
+ })
+ // add remaining fields
+ $.each(doc_fields, function(j, f) {
+ if (f && !in_list(column_names, f.fieldname)
+ && !in_list(["Section Break", "Column Break"], f.fieldtype) && f.label) {
+ fields.push(f);
+ }
+ })
// render checkboxes
$(frappe.render_template("print_format_builder_column_selector", {
- fields: frappe.get_meta(doctype).fields,
+ fields: fields,
column_names: column_names,
widths: widths
})).appendTo(d.body);
@@ -520,7 +547,10 @@ frappe.PrintFormatBuilder = Class.extend({
});
},
get_visible_columns_string: function(f) {
- return $.map(f.visible_columns, function(v) { return v.fieldname + "|" + (v.print_width || "") }).join(",")
+ if(!f.visible_columns) {
+ this.init_visible_columns(f);
+ }
+ return $.map(f.visible_columns, function(v) { return v.fieldname + "|" + (v.print_width || "") }).join(",");
},
get_no_content: function() {
return ''
diff --git a/frappe/print/page/print_format_builder/print_format_builder_column_selector.html b/frappe/print/page/print_format_builder/print_format_builder_column_selector.html
index f6b645aac9..28106b9b14 100644
--- a/frappe/print/page/print_format_builder/print_format_builder_column_selector.html
+++ b/frappe/print/page/print_format_builder/print_format_builder_column_selector.html
@@ -6,8 +6,7 @@
').appendTo(this.parent);
}
},
+ toggle_label: function(show) {
+ this.$wrapper.find(".control-label").toggleClass("hide", !show);
+ },
+ toggle_description: function(show) {
+ this.$wrapper.find(".help-box").toggleClass("hide", !show);
+ },
set_input_areas: function() {
if(this.only_input) {
this.input_area = this.wrapper;
@@ -236,6 +258,7 @@ frappe.ui.form.ControlInput = frappe.ui.form.Control.extend({
me.set_description();
me.set_label();
me.set_mandatory(me.value);
+ me.set_bold();
}
return false;
});
@@ -296,12 +319,6 @@ frappe.ui.form.ControlInput = frappe.ui.form.Control.extend({
if(this.only_input || this.df.label==this._label)
return;
- // var icon = frappe.ui.form.fieldtype_icons[this.df.fieldtype];
- // if(this.df.fieldtype==="Link") {
- // icon = frappe.boot.doctype_icons[this.df.options];
- // } else if(this.df.link_doctype) {
- // icon = frappe.boot.doctype_icons[this.df.link_doctype];
- // }
var icon = "";
this.label_span.innerHTML = (icon ? '
' : "") +
__(this.df.label) || " ";
@@ -323,6 +340,14 @@ frappe.ui.form.ControlInput = frappe.ui.form.Control.extend({
set_mandatory: function(value) {
this.$wrapper.toggleClass("has-error", (this.df.reqd && is_null(value)) ? true : false);
},
+ set_bold: function() {
+ if(this.$input) {
+ this.$input.toggleClass("bold", !!this.df.bold);
+ }
+ if(this.disp_area) {
+ $(this.disp_area).toggleClass("bold", !!this.df.bold);
+ }
+ }
});
frappe.ui.form.ControlData = frappe.ui.form.ControlInput.extend({
@@ -334,6 +359,11 @@ frappe.ui.form.ControlData = frappe.ui.form.ControlInput.extend({
.addClass("input-with-feedback form-control")
.prependTo(this.input_area)
+ if (in_list(['Data', 'Link', 'Dynamic Link', 'Password', 'Select', 'Read Only', 'Attach', 'Attach Image'],
+ this.df.fieldtype)) {
+ this.$input.attr("maxlength", this.df.length || 140);
+ }
+
this.set_input_attributes();
this.input = this.$input.get(0);
this.has_input = true;
@@ -493,10 +523,12 @@ frappe.ui.form.ControlDate = frappe.ui.form.ControlData.extend({
datepicker_options: {
altFormat:'yy-mm-dd',
changeYear: true,
+ changeMonth: true,
yearRange: "-70Y:+10Y",
},
make_input: function() {
this._super();
+ this.set_t_for_today();
this.set_datepicker();
},
set_datepicker: function() {
@@ -504,6 +536,15 @@ frappe.ui.form.ControlDate = frappe.ui.form.ControlData.extend({
(frappe.boot.sysdefaults.date_format || 'yyyy-mm-dd').replace("yyyy", "yy")
this.$input.datepicker(this.datepicker_options);
},
+ set_t_for_today: function() {
+ var me = this;
+ this.$input.on("keydown", function(e) {
+ if(e.which===84) { // 84 === t
+ me.set_value(frappe.datetime.str_to_user(frappe.datetime.nowdate()));
+ return false;
+ }
+ });
+ },
parse: function(value) {
if(value) {
value = dateutil.user_to_str(value);
@@ -547,9 +588,13 @@ frappe.ui.form.ControlTime = frappe.ui.form.ControlData.extend({
frappe.ui.form.ControlDatetime = frappe.ui.form.ControlDate.extend({
set_datepicker: function() {
- this.datepicker_options.timeFormat = "HH:mm:ss";
- this.datepicker_options.dateFormat =
- (frappe.boot.sysdefaults.date_format || 'yy-mm-dd').replace('yyyy','yy');
+ var now = new Date();
+ $.extend(this.datepicker_options, {
+ "timeFormat": "HH:mm:ss",
+ "dateFormat": (frappe.boot.sysdefaults.date_format || 'yy-mm-dd').replace('yyyy','yy'),
+ "hour": now.getHours(),
+ "minute": now.getMinutes()
+ });
this.$input.datetimepicker(this.datepicker_options);
},
@@ -625,7 +670,7 @@ frappe.ui.form.ControlCheck = frappe.ui.form.ControlData.extend({
frappe.ui.form.ControlButton = frappe.ui.form.ControlData.extend({
make_input: function() {
var me = this;
- this.$input = $('