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:
commit
1bd0cfdfde
11 changed files with 401 additions and 2597 deletions
58
cypress/integration/depends_on.js
Normal file
58
cypress/integration/depends_on.js
Normal 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
|
|
@ -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 \
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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'}):
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue