ソースを参照

Merge branch 'develop' of https://github.com/frappe/frappe into python-distributed-testing

version-14
Suraj Shetty 4年前
コミット
6bf9f47a2a
8個のファイルの変更139行の追加25行の削除
  1. +1
    -1
      frappe/automation/doctype/auto_repeat/auto_repeat.js
  2. +61
    -4
      frappe/core/doctype/doctype/doctype.py
  3. +2
    -2
      frappe/custom/doctype/custom_field/custom_field.py
  4. +0
    -0
      frappe/email/doctype/newsletter/newsletter..json
  5. +3
    -2
      frappe/model/base_document.py
  6. +31
    -2
      frappe/model/naming.py
  7. +13
    -8
      frappe/public/js/frappe/desk.js
  8. +28
    -6
      frappe/tests/test_naming.py

+ 1
- 1
frappe/automation/doctype/auto_repeat/auto_repeat.js ファイルの表示

@@ -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 || []


+ 61
- 4
frappe/core/doctype/doctype/doctype.py ファイルの表示

@@ -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():


+ 2
- 2
frappe/custom/doctype/custom_field/custom_field.py ファイルの表示

@@ -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:


+ 0
- 0
frappe/email/doctype/newsletter/newsletter..json ファイルの表示


+ 3
- 2
frappe/model/base_document.py ファイルの表示

@@ -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"):


+ 31
- 2
frappe/model/naming.py ファイルの表示

@@ -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



+ 13
- 8
frappe/public/js/frappe/desk.js ファイルの表示

@@ -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() {


+ 28
- 6
frappe/tests/test_naming.py ファイルの表示

@@ -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)

読み込み中…
キャンセル
保存