Merge branch 'develop' of https://github.com/frappe/frappe into python-distributed-testing
This commit is contained in:
commit
6bf9f47a2a
8 changed files with 139 additions and 25 deletions
|
|
@ -103,7 +103,7 @@ frappe.ui.form.on('Auto Repeat', {
|
|||
frappe.auto_repeat.render_schedule = function(frm) {
|
||||
if (!frm.is_dirty() && frm.doc.status !== 'Disabled') {
|
||||
frm.call("get_auto_repeat_schedule").then(r => {
|
||||
frm.dashboard.wrapper.empty();
|
||||
frm.dashboard.reset();
|
||||
frm.dashboard.add_section(
|
||||
frappe.render_template("auto_repeat_schedule", {
|
||||
schedule_details: r.message || []
|
||||
|
|
|
|||
|
|
@ -83,12 +83,61 @@ class DocType(Document):
|
|||
if not self.is_new():
|
||||
self.before_update = frappe.get_doc('DocType', self.name)
|
||||
self.setup_fields_to_fetch()
|
||||
self.validate_field_name_conflicts()
|
||||
|
||||
check_email_append_to(self)
|
||||
|
||||
if self.default_print_format and not self.custom:
|
||||
frappe.throw(_('Standard DocType cannot have default print format, use Customize Form'))
|
||||
|
||||
if frappe.conf.get('developer_mode'):
|
||||
self.owner = 'Administrator'
|
||||
self.modified_by = 'Administrator'
|
||||
|
||||
def validate_field_name_conflicts(self):
|
||||
"""Check if field names dont conflict with controller properties and methods"""
|
||||
core_doctypes = [
|
||||
"Custom DocPerm",
|
||||
"DocPerm",
|
||||
"Custom Field",
|
||||
"Customize Form Field",
|
||||
"DocField",
|
||||
]
|
||||
|
||||
if self.name in core_doctypes:
|
||||
return
|
||||
|
||||
from frappe.model.base_document import get_controller
|
||||
|
||||
try:
|
||||
controller = get_controller(self.name)
|
||||
except ImportError:
|
||||
controller = Document
|
||||
|
||||
available_objects = {x for x in dir(controller) if isinstance(x, str)}
|
||||
property_set = {
|
||||
x for x in available_objects if isinstance(getattr(controller, x, None), property)
|
||||
}
|
||||
method_set = {
|
||||
x for x in available_objects if x not in property_set and callable(getattr(controller, x, None))
|
||||
}
|
||||
|
||||
for docfield in self.get("fields") or []:
|
||||
conflict_type = None
|
||||
field = docfield.fieldname
|
||||
field_label = docfield.label or docfield.fieldname
|
||||
|
||||
if docfield.fieldname in method_set:
|
||||
conflict_type = "controller method"
|
||||
if docfield.fieldname in property_set:
|
||||
conflict_type = "class property"
|
||||
|
||||
if conflict_type:
|
||||
frappe.throw(
|
||||
_("Fieldname '{0}' conflicting with a {1} of the name {2} in {3}")
|
||||
.format(field_label, conflict_type, field, self.name)
|
||||
)
|
||||
|
||||
def after_insert(self):
|
||||
# clear user cache so that on the next reload this doctype is included in boot
|
||||
clear_user_cache(frappe.session.user)
|
||||
|
|
@ -1174,11 +1223,19 @@ def make_module_and_roles(doc, perm_fieldname="permissions"):
|
|||
else:
|
||||
raise
|
||||
|
||||
def check_if_fieldname_conflicts_with_methods(doctype, fieldname):
|
||||
doc = frappe.get_doc({"doctype": doctype})
|
||||
method_list = [method for method in dir(doc) if isinstance(method, str) and callable(getattr(doc, method))]
|
||||
def check_fieldname_conflicts(doctype, fieldname):
|
||||
"""Checks if fieldname conflicts with methods or properties"""
|
||||
|
||||
if fieldname in method_list:
|
||||
doc = frappe.get_doc({"doctype": doctype})
|
||||
available_objects = [x for x in dir(doc) if isinstance(x, str)]
|
||||
property_list = [
|
||||
x for x in available_objects if isinstance(getattr(type(doc), x, None), property)
|
||||
]
|
||||
method_list = [
|
||||
x for x in available_objects if x not in property_list and callable(getattr(doc, x))
|
||||
]
|
||||
|
||||
if fieldname in method_list + property_list:
|
||||
frappe.throw(_("Fieldname {0} conflicting with meta object").format(fieldname))
|
||||
|
||||
def clear_linked_doctype_cache():
|
||||
|
|
|
|||
|
|
@ -64,8 +64,8 @@ class CustomField(Document):
|
|||
self.translatable = 0
|
||||
|
||||
if not self.flags.ignore_validate:
|
||||
from frappe.core.doctype.doctype.doctype import check_if_fieldname_conflicts_with_methods
|
||||
check_if_fieldname_conflicts_with_methods(self.dt, self.fieldname)
|
||||
from frappe.core.doctype.doctype.doctype import check_fieldname_conflicts
|
||||
check_fieldname_conflicts(self.dt, self.fieldname)
|
||||
|
||||
def on_update(self):
|
||||
if not frappe.flags.in_setup_wizard:
|
||||
|
|
|
|||
|
|
@ -34,8 +34,9 @@ def get_controller(doctype):
|
|||
from frappe.model.document import Document
|
||||
from frappe.utils.nestedset import NestedSet
|
||||
|
||||
module_name, custom = frappe.db.get_value("DocType", doctype, ("module", "custom"), cache=True) \
|
||||
or ["Core", False]
|
||||
module_name, custom = frappe.db.get_value(
|
||||
"DocType", doctype, ("module", "custom"), cache=True
|
||||
) or ["Core", False]
|
||||
|
||||
if custom:
|
||||
if frappe.db.field_exists("DocType", "is_tree"):
|
||||
|
|
|
|||
|
|
@ -199,10 +199,39 @@ def getseries(key, digits):
|
|||
|
||||
|
||||
def revert_series_if_last(key, name, doc=None):
|
||||
if ".#" in key:
|
||||
"""
|
||||
Reverts the series for particular naming series:
|
||||
* key is naming series - SINV-.YYYY-.####
|
||||
* name is actual name - SINV-2021-0001
|
||||
|
||||
1. This function split the key into two parts prefix (SINV-YYYY) & hashes (####).
|
||||
2. Use prefix to get the current index of that naming series from Series table
|
||||
3. Then revert the current index.
|
||||
|
||||
*For custom naming series:*
|
||||
1. hash can exist anywhere, if it exist in hashes then it take normal flow.
|
||||
2. If hash doesn't exit in hashes, we get the hash from prefix, then update name and prefix accordingly.
|
||||
|
||||
*Example:*
|
||||
1. key = SINV-.YYYY.-
|
||||
* If key doesn't have hash it will add hash at the end
|
||||
* prefix will be SINV-YYYY based on this will get current index from Series table.
|
||||
2. key = SINV-.####.-2021
|
||||
* now prefix = SINV-#### and hashes = 2021 (hash doesn't exist)
|
||||
* will search hash in key then accordingly get prefix = SINV-
|
||||
3. key = ####.-2021
|
||||
* prefix = #### and hashes = 2021 (hash doesn't exist)
|
||||
* will search hash in key then accordingly get prefix = ""
|
||||
"""
|
||||
if ".#" in key:
|
||||
prefix, hashes = key.rsplit(".", 1)
|
||||
if "#" not in hashes:
|
||||
return
|
||||
# get the hash part from the key
|
||||
hash = re.search("#+", key)
|
||||
if not hash:
|
||||
return
|
||||
name = name.replace(hashes, "")
|
||||
prefix = prefix.replace(hash.group(), "")
|
||||
else:
|
||||
prefix = key
|
||||
|
||||
|
|
|
|||
|
|
@ -474,14 +474,19 @@ frappe.Application = Class.extend({
|
|||
$('<link rel="icon" href="' + link + '" type="image/x-icon">').appendTo("head");
|
||||
},
|
||||
trigger_primary_action: function() {
|
||||
if(window.cur_dialog && cur_dialog.display) {
|
||||
// trigger primary
|
||||
cur_dialog.get_primary_btn().trigger("click");
|
||||
} else if(cur_frm && cur_frm.page.btn_primary.is(':visible')) {
|
||||
cur_frm.page.btn_primary.trigger('click');
|
||||
} else if(frappe.container.page.save_action) {
|
||||
frappe.container.page.save_action();
|
||||
}
|
||||
// to trigger change event on active input before triggering primary action
|
||||
$(document.activeElement).blur();
|
||||
// wait for possible JS validations triggered after blur (it might change primary button)
|
||||
setTimeout(() => {
|
||||
if (window.cur_dialog && cur_dialog.display) {
|
||||
// trigger primary
|
||||
cur_dialog.get_primary_btn().trigger("click");
|
||||
} else if (cur_frm && cur_frm.page.btn_primary.is(':visible')) {
|
||||
cur_frm.page.btn_primary.trigger('click');
|
||||
} else if (frappe.container.page.save_action) {
|
||||
frappe.container.page.save_action();
|
||||
}
|
||||
}, 100);
|
||||
},
|
||||
|
||||
set_rtl: function() {
|
||||
|
|
|
|||
|
|
@ -70,9 +70,9 @@ class TestNaming(unittest.TestCase):
|
|||
name = 'TEST-{}-00001'.format(year)
|
||||
frappe.db.sql("""INSERT INTO `tabSeries` (name, current) values (%s, 1)""", (series,))
|
||||
revert_series_if_last(key, name)
|
||||
count = frappe.db.sql("""SELECT current from `tabSeries` where name = %s""", series, as_dict=True)[0]
|
||||
current_index = frappe.db.sql("""SELECT current from `tabSeries` where name = %s""", series, as_dict=True)[0]
|
||||
|
||||
self.assertEqual(count.get('current'), 0)
|
||||
self.assertEqual(current_index.get('current'), 0)
|
||||
frappe.db.sql("""delete from `tabSeries` where name = %s""", series)
|
||||
|
||||
series = 'TEST-{}-'.format(year)
|
||||
|
|
@ -80,9 +80,9 @@ class TestNaming(unittest.TestCase):
|
|||
name = 'TEST-{}-00002'.format(year)
|
||||
frappe.db.sql("""INSERT INTO `tabSeries` (name, current) values (%s, 2)""", (series,))
|
||||
revert_series_if_last(key, name)
|
||||
count = frappe.db.sql("""SELECT current from `tabSeries` where name = %s""", series, as_dict=True)[0]
|
||||
current_index = frappe.db.sql("""SELECT current from `tabSeries` where name = %s""", series, as_dict=True)[0]
|
||||
|
||||
self.assertEqual(count.get('current'), 1)
|
||||
self.assertEqual(current_index.get('current'), 1)
|
||||
frappe.db.sql("""delete from `tabSeries` where name = %s""", series)
|
||||
|
||||
series = 'TEST-'
|
||||
|
|
@ -91,7 +91,29 @@ class TestNaming(unittest.TestCase):
|
|||
frappe.db.sql("DELETE FROM `tabSeries` WHERE `name`=%s", series)
|
||||
frappe.db.sql("""INSERT INTO `tabSeries` (name, current) values (%s, 3)""", (series,))
|
||||
revert_series_if_last(key, name)
|
||||
count = frappe.db.sql("""SELECT current from `tabSeries` where name = %s""", series, as_dict=True)[0]
|
||||
current_index = frappe.db.sql("""SELECT current from `tabSeries` where name = %s""", series, as_dict=True)[0]
|
||||
|
||||
self.assertEqual(count.get('current'), 2)
|
||||
self.assertEqual(current_index.get('current'), 2)
|
||||
frappe.db.sql("""delete from `tabSeries` where name = %s""", series)
|
||||
|
||||
series = 'TEST1-'
|
||||
key = 'TEST1-.#####.-2021-22'
|
||||
name = 'TEST1-00003-2021-22'
|
||||
frappe.db.sql("DELETE FROM `tabSeries` WHERE `name`=%s", series)
|
||||
frappe.db.sql("""INSERT INTO `tabSeries` (name, current) values (%s, 3)""", (series,))
|
||||
revert_series_if_last(key, name)
|
||||
current_index = frappe.db.sql("""SELECT current from `tabSeries` where name = %s""", series, as_dict=True)[0]
|
||||
|
||||
self.assertEqual(current_index.get('current'), 2)
|
||||
frappe.db.sql("""delete from `tabSeries` where name = %s""", series)
|
||||
|
||||
series = ''
|
||||
key = '.#####.-2021-22'
|
||||
name = '00003-2021-22'
|
||||
frappe.db.sql("DELETE FROM `tabSeries` WHERE `name`=%s", series)
|
||||
frappe.db.sql("""INSERT INTO `tabSeries` (name, current) values (%s, 3)""", (series,))
|
||||
revert_series_if_last(key, name)
|
||||
current_index = frappe.db.sql("""SELECT current from `tabSeries` where name = %s""", series, as_dict=True)[0]
|
||||
|
||||
self.assertEqual(current_index.get('current'), 2)
|
||||
frappe.db.sql("""delete from `tabSeries` where name = %s""", series)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue