Merge pull request #8820 from prssanna/mandatory-depends-on

feat: Add Mandatory Depends On and Read Only Depends On to Docfield
This commit is contained in:
mergify[bot] 2019-12-27 10:17:38 +00:00 committed by GitHub
commit 1bd0cfdfde
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 401 additions and 2597 deletions

View file

@ -0,0 +1,58 @@
context('Depends On', () => {
before(() => {
cy.login();
cy.visit('/desk');
cy.window().its('frappe').then(frappe => {
frappe.call('frappe.tests.ui_test_helpers.create_doctype', {
name: 'Test Depends On',
fields: [
{
"label": "Test Field",
"fieldname": "test_field",
"fieldtype": "Data",
},
{
"label": "Dependant Field",
"fieldname": "dependant_field",
"fieldtype": "Data",
"mandatory_depends_on": "eval:doc.test_field=='Some Value'",
"read_only_depends_on": "eval:doc.test_field=='Some Other Value'",
},
{
"label": "Display Dependant Field",
"fieldname": "display_dependant_field",
"fieldtype": "Data",
'depends_on': "eval:doc.test_field=='Value'"
},
]
});
});
});
it('should set the field as mandatory depending on other fields value', () => {
cy.new_form('Test Depends On');
cy.fill_field('test_field', 'Some Value');
cy.get('button.primary-action').contains('Save').click();
cy.get('.msgprint-dialog .modal-title').contains('Missing Fields').should('be.visible');
cy.get('body').click();
cy.fill_field('test_field', 'Random value');
cy.get('button.primary-action').contains('Save').click();
cy.get('.msgprint-dialog .modal-title').contains('Missing Fields').should('not.be.visible');
});
it('should set the field as read only depending on other fields value', () => {
cy.new_form('Test Depends On');
cy.fill_field('dependant_field', 'Some Value');
cy.fill_field('test_field', 'Some Other Value');
cy.get('body').click();
cy.get('.control-input [data-fieldname="dependant_field"]').should('be.disabled');
cy.fill_field('test_field', 'Random Value');
cy.get('body').click();
cy.get('.control-input [data-fieldname="dependant_field"]').should('not.be.disabled');
});
it('should display the field depending on other fields value', () => {
cy.get('.control-input [data-fieldname="display_dependant_field"]').should('not.be.visible');
cy.get('.control-input [data-fieldname="test_field"]').clear();
cy.fill_field('test_field', 'Value');
cy.get('body').click();
cy.get('.control-input [data-fieldname="display_dependant_field"]').should('be.visible');
});
});

File diff suppressed because it is too large Load diff

View file

@ -905,7 +905,7 @@ def validate_fields(meta):
def check_illegal_depends_on_conditions(docfield):
''' assignment operation should not be allowed in the depends on condition.'''
depends_on_fields = ["depends_on", "collapsible_depends_on"]
depends_on_fields = ["depends_on", "collapsible_depends_on", "mandatory_depends_on", "read_only_depends_on"]
for field in depends_on_fields:
depends_on = docfield.get(field, None)
if depends_on and ("=" in depends_on) and \

View file

@ -96,14 +96,19 @@ class TestDocType(unittest.TestCase):
def test_all_depends_on_fields_conditions(self):
import re
docfields = frappe.get_all("DocField", or_filters={
docfields = frappe.get_all("DocField",
or_filters={
"ifnull(depends_on, '')": ("!=", ''),
"ifnull(collapsible_depends_on, '')": ("!=", '')
}, fields=["parent", "depends_on", "collapsible_depends_on", "fieldname", "fieldtype"])
"ifnull(collapsible_depends_on, '')": ("!=", ''),
"ifnull(mandatory_depends_on, '')": ("!=", ''),
"ifnull(read_only_depends_on, '')": ("!=", '')
},
fields=["parent", "depends_on", "collapsible_depends_on", "mandatory_depends_on",\
"read_only_depends_on", "fieldname", "fieldtype"])
pattern = """[\w\.:_]+\s*={1}\s*[\w\.@'"]+"""
for field in docfields:
for depends_on in ["depends_on", "collapsible_depends_on"]:
for depends_on in ["depends_on", "collapsible_depends_on", "mandatory_depends_on", "read_only_depends_on"]:
condition = field.get(depends_on)
if condition:
self.assertFalse(re.match(pattern, condition))

View file

@ -1,4 +1,5 @@
{
"actions": [],
"allow_import": 1,
"creation": "2013-01-10 16:34:01",
"description": "Adds a custom field to a DocType",
@ -24,10 +25,8 @@
"collapsible_depends_on",
"default",
"depends_on",
"description",
"permlevel",
"width",
"columns",
"mandatory_depends_on",
"read_only_depends_on",
"properties",
"reqd",
"unique",
@ -46,7 +45,11 @@
"report_hide",
"search_index",
"ignore_xss_filter",
"translatable"
"translatable",
"description",
"permlevel",
"width",
"columns"
],
"fields": [
{
@ -349,11 +352,24 @@
"fieldname": "length",
"fieldtype": "Int",
"label": "Length"
},
{
"fieldname": "mandatory_depends_on",
"fieldtype": "Code",
"label": "Mandatory Depends On",
"length": 255
},
{
"fieldname": "read_only_depends_on",
"fieldtype": "Code",
"label": "Read Only Depends On",
"length": 255
}
],
"icon": "fa fa-glass",
"idx": 1,
"modified": "2019-09-11 12:57:19.268934",
"links": [],
"modified": "2019-12-12 21:31:08.209996",
"modified_by": "Administrator",
"module": "Custom",
"name": "Custom Field",

View file

@ -59,6 +59,8 @@ docfield_properties = {
'report_hide': 'Check',
'allow_on_submit': 'Check',
'translatable': 'Check',
'mandatory_depends_on': 'Data',
'read_only_depends_on': 'Data',
'depends_on': 'Data',
'description': 'Text',
'default': 'Text',

View file

@ -40,6 +40,8 @@ CREATE TABLE `tabDocField` (
`show_preview_popup` int(1) NOT NULL DEFAULT 0,
`trigger` varchar(255) DEFAULT NULL,
`collapsible_depends_on` text,
`mandatory_depends_on` text,
`read_only_depends_on` text,
`depends_on` text,
`permlevel` int(11) NOT NULL DEFAULT 0,
`ignore_user_permissions` int(1) NOT NULL DEFAULT 0,

View file

@ -40,6 +40,8 @@ CREATE TABLE "tabDocField" (
"show_preview_popup" smallint NOT NULL DEFAULT 0,
"trigger" varchar(255) DEFAULT NULL,
"collapsible_depends_on" text,
"mandatory_depends_on" text,
"read_only_depends_on" text,
"depends_on" text,
"permlevel" bigint NOT NULL DEFAULT 0,
"ignore_user_permissions" smallint NOT NULL DEFAULT 0,

View file

@ -451,27 +451,27 @@ frappe.ui.form.Layout = Class.extend({
// build dependants' dictionary
var has_dep = false;
for(var fkey in this.fields_list) {
for (var fkey in this.fields_list) {
var f = this.fields_list[fkey];
f.dependencies_clear = true;
if(f.df.depends_on) {
if (f.df.depends_on || f.df.mandatory_depends_on || f.df.read_only_depends_on) {
has_dep = true;
}
}
if(!has_dep)return;
if (!has_dep) return;
// show / hide based on values
for(var i=me.fields_list.length-1;i>=0;i--) {
for (var i=me.fields_list.length-1;i>=0;i--) {
var f = me.fields_list[i];
f.guardian_has_value = true;
if(f.df.depends_on) {
if (f.df.depends_on) {
// evaluate guardian
f.guardian_has_value = this.evaluate_depends_on_value(f.df.depends_on);
// show / hide
if(f.guardian_has_value) {
if (f.guardian_has_value) {
if(f.df.hidden_due_to_dependency) {
f.df.hidden_due_to_dependency = false;
f.refresh();
@ -483,10 +483,28 @@ frappe.ui.form.Layout = Class.extend({
}
}
}
if (f.df.mandatory_depends_on) {
this.set_dependant_property(f.df.mandatory_depends_on, f.df.fieldname, 'reqd');
}
if (f.df.read_only_depends_on) {
this.set_dependant_property(f.df.read_only_depends_on, f.df.fieldname, 'read_only');
}
}
this.refresh_section_count();
},
set_dependant_property: function(condition, fieldname, property) {
let set_property = this.evaluate_depends_on_value(condition);
if (this.frm) {
if (set_property) {
this.frm.set_df_property(fieldname, property, 1);
} else {
this.frm.set_df_property(fieldname, property, 0);
}
}
},
evaluate_depends_on_value: function(expression) {
var out = null;
var doc = this.doc;

View file

@ -75,6 +75,23 @@ def create_contact_phone_nos_records():
doc.append('phone_nos', {'phone': '123456{}'.format(index)})
doc.insert()
@frappe.whitelist()
def create_doctype(name, fields):
fields = frappe.parse_json(fields)
if frappe.db.exists('DocType', name):
return
frappe.get_doc({
"doctype": "DocType",
"module": "Core",
"custom": 1,
"fields": fields,
"permissions": [{
"role": "System Manager",
"read": 1
}],
"name": name
}).insert()
@frappe.whitelist()
def create_contact_records():
if frappe.db.get_all('Contact', {'first_name': 'Test Form Contact 1'}):